feat(credential_accessor.py): fix upserting new credentials via accessor

This commit is contained in:
Krrish Dholakia 2025-03-12 19:03:37 -07:00
parent de1f94154b
commit d024a5d703
4 changed files with 45 additions and 24 deletions

View file

@ -21,8 +21,10 @@ class CredentialAccessor:
def upsert_credentials(credentials: List[CredentialItem]): def upsert_credentials(credentials: List[CredentialItem]):
"""Add a credential to the list of credentials.""" """Add a credential to the list of credentials."""
credential_names = [cred.credential_name for cred in litellm.credential_list]
for credential in credentials: for credential in credentials:
if credential.credential_name in litellm.credential_list: if credential.credential_name in credential_names:
# Find and replace the existing credential in the list # Find and replace the existing credential in the list
for i, existing_cred in enumerate(litellm.credential_list): for i, existing_cred in enumerate(litellm.credential_list):
if existing_cred.credential_name == credential.credential_name: if existing_cred.credential_name == credential.credential_name:

View file

@ -85,7 +85,7 @@ async def get_credentials(
masked_credentials = [ masked_credentials = [
{ {
"credential_name": credential.credential_name, "credential_name": credential.credential_name,
"credential_values": credential.credential_values, "credential_info": credential.credential_info,
} }
for credential in litellm.credential_list for credential in litellm.credential_list
] ]

View file

@ -13,7 +13,7 @@ import {
} from "@tremor/react"; } from "@tremor/react";
import { UploadProps } from "antd/es/upload"; import { UploadProps } from "antd/es/upload";
import { PlusIcon } from "@heroicons/react/solid"; import { PlusIcon } from "@heroicons/react/solid";
import { getCredentialsList, credentialCreateCall } from "@/components/networking"; // Assume this is your networking function import { credentialListCall, credentialCreateCall } from "@/components/networking"; // Assume this is your networking function
import AddCredentialsTab from "./add_credentials_tab"; import AddCredentialsTab from "./add_credentials_tab";
import { Form, message } from "antd"; import { Form, message } from "antd";
interface CredentialsPanelProps { interface CredentialsPanelProps {
@ -27,16 +27,11 @@ interface CredentialsResponse {
interface CredentialItem { interface CredentialItem {
credential_name: string | null; credential_name: string | null;
provider: string; credential_values: object;
credential_values: {
api_key?: string;
api_base?: string;
};
credential_info: { credential_info: {
custom_llm_provider?: string;
description?: string; description?: string;
type: string; required?: boolean;
required: boolean;
default?: string;
}; };
} }
@ -78,7 +73,7 @@ const CredentialsPanel: React.FC<CredentialsPanelProps> = ({ accessToken, upload
const fetchCredentials = async () => { const fetchCredentials = async () => {
try { try {
const response: CredentialsResponse = await getCredentialsList(accessToken); const response: CredentialsResponse = await credentialListCall(accessToken);
console.log(`credentials: ${JSON.stringify(response)}`); console.log(`credentials: ${JSON.stringify(response)}`);
setCredentialsList(response.credentials); setCredentialsList(response.credentials);
} catch (error) { } catch (error) {
@ -127,7 +122,6 @@ const CredentialsPanel: React.FC<CredentialsPanelProps> = ({ accessToken, upload
<TableHeaderCell>Credential Name</TableHeaderCell> <TableHeaderCell>Credential Name</TableHeaderCell>
<TableHeaderCell>Provider</TableHeaderCell> <TableHeaderCell>Provider</TableHeaderCell>
<TableHeaderCell>Description</TableHeaderCell> <TableHeaderCell>Description</TableHeaderCell>
<TableHeaderCell>Required</TableHeaderCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@ -142,18 +136,9 @@ const CredentialsPanel: React.FC<CredentialsPanelProps> = ({ accessToken, upload
<TableRow key={index}> <TableRow key={index}>
<TableCell>{credential.credential_name}</TableCell> <TableCell>{credential.credential_name}</TableCell>
<TableCell> <TableCell>
{renderProviderBadge(credential.provider)} {renderProviderBadge(credential.credential_info?.custom_llm_provider as string || '-')}
</TableCell>
<TableCell>{credential.credential_info.description || '-'}</TableCell>
<TableCell>
<div className={`inline-flex rounded-full px-2 py-1 text-xs font-medium
${credential.credential_info.required
? 'bg-green-100 text-green-800' // Required styling
: 'bg-gray-100 text-gray-800' // Optional styling
}`}>
{credential.credential_info.required ? 'Required' : 'Optional'}
</div>
</TableCell> </TableCell>
<TableCell>{credential.credential_info?.description || '-'}</TableCell>
</TableRow> </TableRow>
)) ))
)} )}

View file

@ -2572,6 +2572,40 @@ export const credentialCreateCall = async (
} }
}; };
export const credentialListCall = async (
accessToken: String,
) => {
/**
* Get all available teams on proxy
*/
try {
let url = proxyBaseUrl ? `${proxyBaseUrl}/credentials` : `/credentials`;
console.log("in credentialListCall");
const response = await fetch(url, {
method: "GET",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorData = await response.text();
handleError(errorData);
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log("/credentials API Response:", data);
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const keyUpdateCall = async ( export const keyUpdateCall = async (
accessToken: string, accessToken: string,
formValues: Record<string, any> // Assuming formValues is an object formValues: Record<string, any> // Assuming formValues is an object