Separate handling for OpenAI and DevChat API keys

- Renamed and split the API key settings in package.json into DevChat and OpenAI specific keys.
- Updated the commands for setting API keys to handle OpenAI and DevChat keys separately.
- Modified the ApiKeyManager to handle and validate OpenAI and DevChat keys separately.
- Updated the status bar view to use the DevChat access key command.
- Adjusted the tests to reflect the new handling of API keys.
This commit is contained in:
bobo.yang 2023-08-03 15:09:34 +08:00
parent c665bc881f
commit e2e761fd16
8 changed files with 93 additions and 24 deletions

View File

@ -107,10 +107,15 @@
"description": "The max number of tokens of a prompt.",
"when": "DevChat.llmModel == 'OpenAI'"
},
"DevChat.API_KEY": {
"DevChat.Access_Key_DevChat": {
"type": "string",
"default": "",
"description": "API key for accessing the LLM model",
"description": "DevChat's secret key for accessing multiple LLM models"
},
"DevChat.Api_Key_OpenAI": {
"type": "string",
"default": "",
"description": "OpenAI's secret key for accessing LLM models. (Leave blank if using DevChat's key.)",
"when": "DevChat.llmModel == 'OpenAI'"
},
"DevChat.API_ENDPOINT": {
@ -205,8 +210,13 @@
"title": "Create Entry"
},
{
"command": "DevChat.OPENAI_API_KEY",
"title": "Input Access Key",
"command": "DevChat.Api_Key_OpenAI",
"title": "Input OpenAI Api Key",
"category": "DevChat"
},
{
"command": "DevChat.Access_Key_DevChat",
"title": "Input DevChat Access Key",
"category": "DevChat"
},
{

View File

@ -64,21 +64,40 @@ function registerAskForFileCommand(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('devchat.askForFile_chinese', callback));
}
export function registerApiKeySettingCommand(context: vscode.ExtensionContext) {
export function registerOpenAiApiKeySettingCommand(context: vscode.ExtensionContext) {
const secretStorage: vscode.SecretStorage = context.secrets;
context.subscriptions.push(
vscode.commands.registerCommand('DevChat.OPENAI_API_KEY', async () => {
vscode.commands.registerCommand('DevChat.Api_Key_OpenAI', async () => {
const passwordInput: string = await vscode.window.showInputBox({
password: true,
title: "Input Access Key",
placeHolder: "Set OPENAI_API_KEY (or DevChat Access Key)"
title: "Input OpenAi Api Key",
placeHolder: "Set OpenAI Api Key.(Leave blank if clearing stored key.)"
}) ?? '';
if (passwordInput.trim() !== "" && !isValidApiKey(passwordInput)) {
UiUtilWrapper.showErrorMessage("Your api key is invalid!");
return ;
}
ApiKeyManager.writeApiKeySecret(passwordInput, "OpenAI");
})
);
}
export function registerDevChatApiKeySettingCommand(context: vscode.ExtensionContext) {
const secretStorage: vscode.SecretStorage = context.secrets;
context.subscriptions.push(
vscode.commands.registerCommand('DevChat.Access_Key_DevChat', async () => {
const passwordInput: string = await vscode.window.showInputBox({
password: true,
title: "Input DevChat Access Key",
placeHolder: "Set DevChat Access Key.(Leave blank if clearing stored key.)"
}) ?? '';
if (passwordInput.trim() !== "" && !isValidApiKey(passwordInput)) {
UiUtilWrapper.showErrorMessage("Your access key is invalid!");
return ;
}
ApiKeyManager.writeApiKeySecret(passwordInput);
ApiKeyManager.writeApiKeySecret(passwordInput, "DevChat");
})
);
}

View File

@ -5,7 +5,8 @@ import {
registerAddContextCommand,
registerAskForCodeCommand,
registerAskForFileCommand,
registerApiKeySettingCommand,
registerOpenAiApiKeySettingCommand,
registerDevChatApiKeySettingCommand,
regTopicDeleteCommand,
regAddTopicCommand,
regDeleteSelectTopicCommand,
@ -37,7 +38,8 @@ function activate(context: vscode.ExtensionContext) {
regDevChatView(context);
regTopicView(context);
registerApiKeySettingCommand(context);
registerOpenAiApiKeySettingCommand(context);
registerDevChatApiKeySettingCommand(context);
registerOpenChatPanelCommand(context);
registerAddContextCommand(context);
registerAskForCodeCommand(context);

View File

@ -45,9 +45,22 @@ OPENAI_API_KEY is missing from your environment or settings. Kindly input your O
} as LogEntry;
}
export function isValidApiKey(apiKey: string) {
export function isValidApiKey(apiKey: string, llmType: string = "None") {
let apiKeyStrim = apiKey.trim();
if (ApiKeyManager.getKeyType(apiKeyStrim) === undefined) {
const apiKeyType = ApiKeyManager.getKeyType(apiKeyStrim);
if (apiKeyType === undefined) {
return false;
}
if (llmType === "OpenAI") {
if (apiKeyType === "sk") {
return true;
}
return false;
}
if (llmType === "DevChat") {
if (apiKeyType === "DC") {
return true;
}
return false;
}
return true;

View File

@ -45,7 +45,7 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
if (apiKeyStatus !== 'ready') {
statusBarItem.text = `$(warning)DevChat`;
statusBarItem.tooltip = `${apiKeyStatus}`;
statusBarItem.command = 'DevChat.OPENAI_API_KEY';
statusBarItem.command = 'DevChat.Access_Key_DevChat';
return;
}

View File

@ -3,14 +3,29 @@
import { UiUtilWrapper } from './uiUtil';
export class ApiKeyManager {
static async getApiKey(): Promise<string | undefined> {
let apiKey = await UiUtilWrapper.secretStorageGet("devchat_OPENAI_API_KEY");
if (!apiKey) {
apiKey = UiUtilWrapper.getConfiguration('DevChat', 'API_KEY');
static async getApiKey(llmType: string = "OpenAI"): Promise<string | undefined> {
let apiKey: string|undefined = undefined;
if (llmType === "OpenAI") {
apiKey = await UiUtilWrapper.secretStorageGet("openai_OPENAI_API_KEY");
}
if (!apiKey) {
apiKey = await UiUtilWrapper.secretStorageGet("devchat_OPENAI_API_KEY");
}
if (!apiKey) {
if (llmType === "OpenAI") {
apiKey = UiUtilWrapper.getConfiguration('DevChat', 'Api_Key_OpenAI');
}
if (!apiKey) {
apiKey = UiUtilWrapper.getConfiguration('DevChat', 'Access_Key_DevChat');
}
}
if (!apiKey) {
if (llmType === "OpenAI") {
apiKey = process.env.OPENAI_API_KEY;
}
}
return apiKey;
}
@ -24,8 +39,18 @@ export class ApiKeyManager {
}
}
static async writeApiKeySecret(apiKey: string): Promise<void> {
static async writeApiKeySecret(apiKey: string, llmType: string = "Unknow"): Promise<void> {
if (apiKey.startsWith("sk-")) {
await UiUtilWrapper.storeSecret("openai_OPENAI_API_KEY", apiKey);
} else if (apiKey.startsWith("DC.")) {
await UiUtilWrapper.storeSecret("devchat_OPENAI_API_KEY", apiKey);
} else {
if (llmType === "OpenAI") {
await UiUtilWrapper.storeSecret("openai_OPENAI_API_KEY", apiKey);
} else if (llmType === "DevChat") {
await UiUtilWrapper.storeSecret("devchat_OPENAI_API_KEY", apiKey);
}
}
}
static getEndPoint(apiKey: string | undefined): string | undefined {

View File

@ -129,7 +129,7 @@ describe('sendMessageBase', () => {
workspaceFoldersFirstPathStub.returns('./');
getConfigurationStub.withArgs('DevChat', 'API_KEY').returns(process.env.TEST_DEVCHAT_KEY);
getConfigurationStub.withArgs('DevChat', 'Access_Key_DevChat').returns(process.env.TEST_DEVCHAT_KEY);
getConfigurationStub.withArgs('DevChat', 'OpenAI.model').returns('gpt-4');
getConfigurationStub.withArgs('DevChat', 'OpenAI.temperature').returns(0);
getConfigurationStub.withArgs('DevChat', 'OpenAI.stream').returns('true');
@ -156,7 +156,7 @@ describe('sendMessageBase', () => {
workspaceFoldersFirstPathStub.returns('./');
getConfigurationStub.withArgs('DevChat', 'API_KEY').returns('sk-KvH7ZCtHmFDCBTqH0jUv');
getConfigurationStub.withArgs('DevChat', 'Access_Key_DevChat').returns('sk-KvH7ZCtHmFDCBTqH0jUv');
getConfigurationStub.withArgs('DevChat', 'OpenAI.model').returns('gpt-4');
getConfigurationStub.withArgs('DevChat', 'OpenAI.temperature').returns('0');
getConfigurationStub.withArgs('DevChat', 'OpenAI.stream').returns('true');
@ -185,7 +185,7 @@ describe('sendMessageBase', () => {
workspaceFoldersFirstPathStub.returns('./');
getConfigurationStub.withArgs('DevChat', 'API_KEY').returns(process.env.TEST_DEVCHAT_KEY);
getConfigurationStub.withArgs('DevChat', 'Access_Key_DevChat').returns(process.env.TEST_DEVCHAT_KEY);
getConfigurationStub.withArgs('DevChat', 'OpenAI.model').returns('gpt-4');
getConfigurationStub.withArgs('DevChat', 'OpenAI.temperature').returns(0);
getConfigurationStub.withArgs('DevChat', 'OpenAI.stream').returns('true');

View File

@ -85,7 +85,7 @@ describe('ApiKeyManager', () => {
const storeSecretStub = sinon.stub(UiUtilWrapper, 'storeSecret').resolves();
await ApiKeyManager.writeApiKeySecret('sk-secret');
expect(storeSecretStub.calledWith('devchat_OPENAI_API_KEY', 'sk-secret')).to.be.true;
expect(storeSecretStub.calledWith('openai_OPENAI_API_KEY', 'sk-secret')).to.be.true;
});
});
});