Skip to content

Commit

Permalink
Merge pull request #1306 from Agenta-AI/fix/llm-provider-keys
Browse files Browse the repository at this point in the history
Fix/llm provider keys
  • Loading branch information
aakrem authored Mar 18, 2024
2 parents 4f7012a + ca436c0 commit 975ac39
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 148 deletions.
3 changes: 2 additions & 1 deletion agenta-web/cypress/support/commands/evaluations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {randString, removeLlmProviderKey} from "../../../src/lib/helpers/utils"
import {randString} from "../../../src/lib/helpers/utils"
import {removeLlmProviderKey} from "../../../src/lib/helpers/llmProviders"

let app_id

Expand Down
20 changes: 4 additions & 16 deletions agenta-web/src/components/AppSelector/AppSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ import {Template, GenericObject} from "@/lib/Types"
import {useAppTheme} from "../Layout/ThemeContextProvider"
import TipsAndFeatures from "./TipsAndFeatures"
import Welcome from "./Welcome"
import {
getAllProviderLlmKeys,
getApikeys,
isAppNameInputValid,
isDemo,
redirectIfNoLLMKeys,
} from "@/lib/helpers/utils"
import {isAppNameInputValid, isDemo, redirectIfNoLLMKeys} from "@/lib/helpers/utils"
import {
createAndStartTemplate,
getTemplates,
Expand All @@ -28,6 +22,7 @@ import {useAppsData} from "@/contexts/app.context"
import {useProfileData} from "@/contexts/profile.context"
import CreateAppStatusModal from "./modals/CreateAppStatusModal"
import {usePostHogAg} from "@/hooks/usePostHogAg"
import {LlmProvider, getAllProviderLlmKeys, getApikeys} from "@/lib/helpers/llmProviders"
import ResultComponent from "../ResultComponent/ResultComponent"
import {dynamicContext} from "@/lib/helpers/dynamic"

Expand Down Expand Up @@ -136,10 +131,6 @@ const AppSelector: React.FC = () => {
})
}, [])

useEffect(() => {
getAllProviderLlmKeys()
}, [])

const showCreateAppModal = async () => {
setIsCreateAppModalOpen(true)
}
Expand Down Expand Up @@ -208,14 +199,11 @@ const AppSelector: React.FC = () => {
setStatusModalOpen(true)

// attempt to create and start the template, notify user of the progress
const apiKey = getApikeys()
const apiKeys = getAllProviderLlmKeys()
await createAndStartTemplate({
appName: newApp,
templateId: template_id,
providerKey:
isDemo() && apiKey?.length === 0
? []
: (apiKey as {title: string; key: string; name: string}[]),
providerKey: isDemo() && apiKeys?.length === 0 ? [] : (apiKeys as LlmProvider[]),
timeout,
onStatusChange: async (status, details, appId) => {
setStatusData((prev) => ({status, details, appId: appId || prev.appId}))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React, {useEffect, useState} from "react"
import {GenericObject, JSSTheme, Parameter, Variant} from "@/lib/Types"
import {createNewEvaluation, fetchVariants, useLoadTestsetsList} from "@/lib/services/api"
import {isDemo} from "@/lib/helpers/utils"
import {Button, Col, Dropdown, MenuProps, Modal, ModalProps, Row, Spin, message} from "antd"
import {getErrorMessage} from "@/lib/helpers/errorHandler"
import {isDemo} from "@/lib/helpers/utils"
import {DownOutlined} from "@ant-design/icons"
import {EvaluationType} from "@/lib/enums"
import {PERMISSION_ERR_MSG} from "@/lib/helpers/axiosConfig"
import {getAllVariantParameters} from "@/lib/helpers/variantHelper"
import {dynamicComponent} from "@/lib/helpers/dynamic"
import {useRouter} from "next/router"
import {useAppTheme} from "../Layout/ThemeContextProvider"
import {createUseStyles} from "react-jss"
import {getApikeys} from "@/lib/helpers/llmProviders"
import EvaluationErrorModal from "../Evaluations/EvaluationErrorModal"
import {dynamicComponent} from "@/lib/helpers/dynamic"

type StyleProps = {
themeMode: "dark" | "light"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useAppId} from "@/hooks/useAppId"
import {JSSTheme, Variant, LLMRunRateLimit, testset} from "@/lib/Types"
import {evaluatorConfigsAtom, evaluatorsAtom} from "@/lib/atoms/evaluation"
import {getAllProviderLlmKeys, apiKeyObject, redirectIfNoLLMKeys} from "@/lib/helpers/utils"
import {apiKeyObject, redirectIfNoLLMKeys} from "@/lib/helpers/utils"
import {fetchTestsets, fetchVariants} from "@/lib/services/api"
import {CreateEvaluationData, createEvalutaiton} from "@/services/evaluations"
import {PlusOutlined, QuestionCircleOutlined} from "@ant-design/icons"
Expand Down Expand Up @@ -79,10 +79,6 @@ const NewEvaluationModal: React.FC<Props> = ({onSuccess, ...props}) => {
const [showAdvancedConfig, setshowAdvancedConfig] = useState(false)
const [form] = Form.useForm()

useEffect(() => {
getAllProviderLlmKeys()
}, [])

useEffect(() => {
setFetching(true)
form.resetFields()
Expand Down
9 changes: 5 additions & 4 deletions agenta-web/src/components/pages/settings/Secrets/Secrets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
removeSingleLlmProviderKey,
getAllProviderLlmKeys,
LlmProvider,
} from "@/lib/helpers/utils"
getApikeys,
} from "@/lib/helpers/llmProviders"
import {Button, Input, Space, Typography, message} from "antd"
import {useState} from "react"
import {createUseStyles} from "react-jss"
Expand Down Expand Up @@ -68,17 +69,17 @@ export default function Secrets() {
/>
<Button
data-cy="openai-api-save"
disabled={key === getLlmProviderKey(key) || !key}
disabled={key === getLlmProviderKey(title) || !key}
onClick={() => {
saveLlmProviderKey(i, key)
saveLlmProviderKey(title, key)
messageAPI.success("The secret is saved")
}}
>
Save
</Button>
<Button
onClick={() => {
removeSingleLlmProviderKey(i)
removeSingleLlmProviderKey(title)

const newLlmProviderKeys = [...llmProviderKeys]
newLlmProviderKeys[i].key = ""
Expand Down
84 changes: 84 additions & 0 deletions agenta-web/src/lib/helpers/llmProviders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import _ from "lodash"
import {camelToSnake} from "./utils"

const llmAvailableProvidersToken = "llmAvailableProvidersToken"

export type LlmProvider = {
title: string
key: string
name: string
}

export const llmAvailableProviders: LlmProvider[] = [
{title: "OpenAI", key: "", name: "OPENAI_API_KEY"},
{title: "Replicate", key: "", name: "REPLICATE_API_KEY"},
{title: "Hugging Face", key: "", name: "HUGGING_FACE_API_KEY"},
{title: "Cohere", key: "", name: "COHERE_API_KEY"},
{title: "Anthropic", key: "", name: "ANTHROPIC_API_KEY"},
{title: "Azure", key: "", name: "AZURE_API_KEY"},
{title: "TogetherAI", key: "", name: "TOGETHERAI_API_KEY"},
]

export const getApikeys = () => {
if (typeof window !== "undefined") {
const llmAvailableProvidersTokenString = localStorage.getItem(llmAvailableProvidersToken)
const apiKeys: Array<LlmProvider> = []

if (llmAvailableProvidersTokenString !== null) {
const llmAvailableProvidersTokenArray = JSON.parse(llmAvailableProvidersTokenString)

if (
Array.isArray(llmAvailableProvidersTokenArray) &&
llmAvailableProvidersTokenArray.length > 0
) {
for (let i = 0; i < llmAvailableProvidersTokenArray.length; i++) {
if (llmAvailableProvidersTokenArray[i].key !== "") {
apiKeys.push(llmAvailableProvidersTokenArray[i])
}
}
}
}
return apiKeys
}
}

export const saveLlmProviderKey = (providerName: string, keyValue: string) => {
// TODO: add encryption here
const keys = getAllProviderLlmKeys()
const item = keys.find((item: LlmProvider) => item.title === providerName)
if (item) item.key = keyValue
localStorage.setItem(llmAvailableProvidersToken, JSON.stringify(keys))
}

export const getLlmProviderKey = (providerName: string) =>
getAllProviderLlmKeys().find((item: LlmProvider) => item.title === providerName)?.key

export const getAllProviderLlmKeys = () => {
const providers = _.cloneDeep(llmAvailableProviders)
try {
if (typeof window !== "undefined") {
const providersInStorage: LlmProvider[] = JSON.parse(
localStorage.getItem(llmAvailableProvidersToken) || "[{}]",
)
for (const provider of providers) {
provider.key = providersInStorage.find((p) => p.title === provider.title)?.key || ""
}
}
} catch (error) {
console.log(error)
}
return providers
}

export const removeSingleLlmProviderKey = (providerName: string) => {
const keys = getAllProviderLlmKeys()
const item = keys.find((item: LlmProvider) => item.title === providerName)
if (item) item.key = ""
localStorage.setItem(llmAvailableProvidersToken, JSON.stringify(keys))
}

export const removeLlmProviderKey = () => {
if (typeof window !== "undefined") {
localStorage.removeItem(llmAvailableProvidersToken)
}
}
124 changes: 7 additions & 117 deletions agenta-web/src/lib/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dayjs from "dayjs"
import utc from "dayjs/plugin/utc"
import {notification} from "antd"
import Router from "next/router"
import {getAllProviderLlmKeys, getApikeys} from "./llmProviders"

if (typeof window !== "undefined") {
//@ts-ignore
Expand All @@ -15,38 +16,6 @@ if (typeof window !== "undefined") {
}
}

const llmAvailableProvidersToken = "llmAvailableProvidersToken"

export type LlmProvider = {
title: string
key: string
name: string
}

export const llmAvailableProviders: LlmProvider[] = [
{title: "OpenAI", key: "", name: "OPENAI_API_KEY"},
{title: "Replicate", key: "", name: "REPLICATE_API_KEY"},
{title: "Hugging Face", key: "", name: "HUGGING_FACE_API_KEY"},
{title: "Cohere", key: "", name: "COHERE_API_KEY"},
{title: "Anthropic", key: "", name: "ANTHROPIC_API_KEY"},
{title: "Azure API Key", key: "", name: "AZURE_API_KEY"},
{title: "Azure API Base", key: "", name: "AZURE_API_BASE"},
{title: "TogetherAI", key: "", name: "TOGETHERAI_API_KEY"},
]

export const getAllLlmProviderKeysAsEnvVariable = () => {
return {
OPENAI_API_KEY: getLlmProviderKey("OpenAI"),
REPLICATE_API_KEY: getLlmProviderKey("Replicate"),
HUGGING_FACE_API_KEY: getLlmProviderKey("Hugging Face"),
COHERE_API_KEY: getLlmProviderKey("Cohere"),
ANTHROPIC_API_KEY: getLlmProviderKey("Anthropic"),
AZURE_API_KEY: getLlmProviderKey("Azure API Key"),
AZURE_API_BASE: getLlmProviderKey("Azure API Base"),
TOGETHERAI_API_KEY: getLlmProviderKey("TogetherAI"),
}
}

export const renameVariables = (name: string) => {
if (name === "inputs") {
return "Prompt Variables"
Expand Down Expand Up @@ -76,94 +45,15 @@ export const EvaluationTypeLabels: Record<EvaluationType, string> = {
[EvaluationType.single_model_test]: "Single Model Test",
}

export const getApikeys = () => {
if (typeof window !== "undefined") {
const llmAvailableProvidersTokenString = localStorage.getItem(llmAvailableProvidersToken)
let apiKeys: Array<{title: string; key: string; name: string}> = []

if (llmAvailableProvidersTokenString !== null) {
const llmAvailableProvidersTokenArray = JSON.parse(llmAvailableProvidersTokenString)

if (
Array.isArray(llmAvailableProvidersTokenArray) &&
llmAvailableProvidersTokenArray.length > 0
) {
for (let i = 0; i < llmAvailableProvidersTokenArray.length; i++) {
if (llmAvailableProvidersTokenArray[i].key !== "") {
apiKeys.push(llmAvailableProvidersTokenArray[i])
}
}
}
}
return apiKeys
}
}

export const apiKeyObject = () => {
const apiKey = getApikeys()
const apiKeys = getAllProviderLlmKeys()

if (!apiKey) return {}
if (!apiKeys) return {}

return apiKey.reduce(
(acc, {key, name}) => {
acc[name] = key
return acc
},
{} as Record<string, string>,
)
}

export const saveLlmProviderKey = (providerIdx: number, keyValue: string) => {
if (typeof window !== "undefined") {
// TODO: add encryption here
const keys = JSON.parse(localStorage.getItem(llmAvailableProvidersToken) ?? "[{}]")
keys[providerIdx].key = keyValue
localStorage.setItem(llmAvailableProvidersToken, JSON.stringify(keys))
}
}

export const getLlmProviderKey = (providerName: string) =>
getAllProviderLlmKeys().find((item: LlmProvider) => item.title === providerName)

export const getAllProviderLlmKeys = () => {
if (typeof window !== "undefined") {
const inStorage = localStorage.getItem(llmAvailableProvidersToken)
if (inStorage) {
const parsedArray = JSON.parse(inStorage)
const updatedLlmAvailableProviders = parsedArray.map(
(item: LlmProvider, index: number) => {
if (!item.hasOwnProperty("name")) {
item.name = llmAvailableProviders[index].name
}
return item
},
)

localStorage.setItem(
llmAvailableProvidersToken,
JSON.stringify(updatedLlmAvailableProviders),
)

return updatedLlmAvailableProviders
}
localStorage.setItem(llmAvailableProvidersToken, JSON.stringify(llmAvailableProviders))
}

return llmAvailableProviders
}

export const removeSingleLlmProviderKey = (providerIdx: number) => {
if (typeof window !== "undefined") {
const keys = JSON.parse(localStorage.getItem(llmAvailableProvidersToken) ?? "[{}]")
keys[providerIdx].key = ""
localStorage.setItem(llmAvailableProvidersToken, JSON.stringify(keys))
}
}

export const removeLlmProviderKey = () => {
if (typeof window !== "undefined") {
localStorage.removeItem(llmAvailableProvidersToken)
}
return apiKeys.reduce((acc: GenericObject, {key, name}: GenericObject) => {
if (key) acc[name] = key
return acc
}, {})
}

export const capitalize = (s: string) => {
Expand Down
6 changes: 3 additions & 3 deletions agenta-web/src/lib/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
AppTemplate,
GenericObject,
Environment,
DeploymentRevisions,
DeploymentRevisionConfig,
CreateCustomEvaluation,
ExecuteCustomEvalCode,
Expand All @@ -25,6 +24,7 @@ import {
fromEvaluationScenarioResponseToEvaluationScenario,
} from "../transformers"
import {EvaluationFlow, EvaluationType} from "../enums"
import {LlmProvider} from "../helpers/llmProviders"
import {getAgentaApiUrl, removeKeys, shortPoll} from "../helpers/utils"
import {dynamicContext} from "../helpers/dynamic"
/**
Expand Down Expand Up @@ -598,7 +598,7 @@ export const createAndStartTemplate = async ({
onStatusChange,
}: {
appName: string
providerKey: Array<{title: string; key: string; name: string}>
providerKey: Array<LlmProvider>
templateId: string
timeout?: number
onStatusChange?: (
Expand All @@ -609,7 +609,7 @@ export const createAndStartTemplate = async ({
}) => {
const apiKeys = providerKey.reduce(
(acc, {key, name}) => {
acc[name] = key
if (key) acc[name] = key
return acc
},
{} as Record<string, string>,
Expand Down

0 comments on commit 975ac39

Please sign in to comment.