feat: read .voidrules for system prompt

This commit is contained in:
Jelf 2024-09-22 17:35:51 +08:00
parent 6d513a1e60
commit 9b130edcfe
6 changed files with 74 additions and 29 deletions

View file

@ -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;
}
}

View file

@ -3,6 +3,7 @@ import { createOpenAI, OpenAIProviderSettings } from '@ai-sdk/openai';
import { AnthropicProviderSettings, createAnthropic } from '@ai-sdk/anthropic'; import { AnthropicProviderSettings, createAnthropic } from '@ai-sdk/anthropic';
import { AzureOpenAIProviderSettings, createAzure } from '@ai-sdk/azure'; import { AzureOpenAIProviderSettings, createAzure } from '@ai-sdk/azure';
import { createOllama, OllamaProviderSettings } from 'ollama-ai-provider'; import { createOllama, OllamaProviderSettings } from 'ollama-ai-provider';
import { getRules } from './getRules';
export type ApiConfig = { export type ApiConfig = {
/** @default 'anthropic' */ /** @default 'anthropic' */
@ -142,24 +143,29 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin
export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText, onFinalMessage, apiConfig }) => { export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText, onFinalMessage, apiConfig }) => {
if (!apiConfig) return { abort: () => { } } if (!apiConfig) return { abort: () => { } }
const provider = apiConfig.provider const provider = apiConfig.provider
// TODO: create an @ai-sdk provider for greptile // TODO: create an @ai-sdk provider for greptile,
if (provider === 'greptile') if (provider === 'greptile')
return sendGreptileMsg({ messages, onText, onFinalMessage, apiConfig }) return sendGreptileMsg({ messages, onText, onFinalMessage, apiConfig })
const model = getAiModel(apiConfig) const model = getAiModel(apiConfig)
const abortController = new AbortController() const abortController = new AbortController()
const abortSignal = abortController.signal const abortSignal = abortController.signal
streamText({
model, getRules().then(rules => {
messages, streamText({
abortSignal, model,
}).then(async (result) => { system: rules || '',
let fullText = '' messages,
for await (const textPart of result.textStream) { abortSignal,
fullText += textPart }).then(async (result) => {
onText(textPart, fullText) let fullText = ''
} for await (const textPart of result.textStream) {
onFinalMessage(fullText) fullText += textPart
onText(textPart, fullText)
}
onFinalMessage(fullText)
})
}) })
return { abort: abortController.abort } return { abort: abortController.abort }
@ -167,20 +173,28 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText,
export const getAiModel = (apiConfig: ApiConfig) => { export const getAiModel = (apiConfig: ApiConfig) => {
switch (apiConfig.provider) { switch (apiConfig.provider) {
case 'openai': return createOpenAI({ case 'openai':
...apiConfig.openai.providerSettings, return createOpenAI({
apiKey: apiConfig.openai.apiKey, ...apiConfig.openai.providerSettings,
})(apiConfig.openai.model || 'gpt-4o') apiKey: apiConfig.openai.apiKey,
case 'anthropic': return createAnthropic({ })(apiConfig.openai.model || 'gpt-4o')
...apiConfig.anthropic.providerSettings,
apiKey: apiConfig.anthropic.apiKey, case 'anthropic':
})(apiConfig.anthropic.model || 'claude-3-5-sonnet-20240620') return createAnthropic({
case 'ollama': return createOllama(apiConfig.ollama.providerSettings)(apiConfig.ollama.model || 'llama3.1') ...apiConfig.anthropic.providerSettings,
case 'azure': return createAzure({ apiKey: apiConfig.anthropic.apiKey,
...apiConfig.azure.providerSettings, })(apiConfig.anthropic.model || 'claude-3-5-sonnet-20240620')
apiKey: apiConfig.azure.apiKey,
resourceName: apiConfig.azure.resourceName, case 'ollama':
})(`${apiConfig.azure.deploymentId}`) 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: default:
throw new Error(`Error: provider was ${apiConfig.provider}, which is not recognized!`) throw new Error(`Error: provider was ${apiConfig.provider}, which is not recognized!`)
} }

View file

@ -115,7 +115,22 @@ export function activate(context: vscode.ExtensionContext) {
// Receive messages in the extension from the sidebar webview (messages are sent using `postMessage`) // Receive messages in the extension from the sidebar webview (messages are sent using `postMessage`)
webview.onDidReceiveMessage(async (m: WebviewMessage) => { 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 // get contents of all file paths
const files = await Promise.all( const files = await Promise.all(

View file

@ -27,6 +27,9 @@ type WebviewMessage = (
// editor -> sidebar // editor -> sidebar
| { type: 'apiConfig', apiConfig: ApiConfig } | { type: 'apiConfig', apiConfig: ApiConfig }
// sidebar -> editor
| { type: 'getRules', rules: string | null }
) )
type Command = WebviewMessage['type'] type Command = WebviewMessage['type']

View file

@ -266,7 +266,7 @@ const Sidebar = () => {
{!selection?.selectionStr ? null {!selection?.selectionStr ? null
: ( : (
<div className="relative"> <div className="relative">
<button <button
onClick={clearSelection} onClick={clearSelection}
className="absolute top-2 right-2 text-white hover:text-gray-300 z-10" className="absolute top-2 right-2 text-white hover:text-gray-300 z-10"
> >

View file

@ -9,7 +9,8 @@ const awaiting: { [c in Command]: ((res: any) => void)[] } = {
"requestFiles": [], "requestFiles": [],
"files": [], "files": [],
"apiConfig": [], "apiConfig": [],
"getApiConfig": [] "getApiConfig": [],
"getRules": []
} }
// use this function to await responses // use this function to await responses