Revert "Litellm dev 01 10 2025 p2 (#7679)"

This reverts commit c4780479a9.
This commit is contained in:
Ishaan Jaff 2025-01-23 15:31:16 -08:00
parent 8f7b9ae1af
commit a609139dde
14 changed files with 67 additions and 285 deletions

View file

@ -105,7 +105,7 @@ jobs:
command: |
pwd
ls
python -m pytest -vv tests/local_testing --cov=litellm --cov-report=xml -x --junitxml=test-results/junit.xml --durations=5 -k "not test_python_38.py and not test_basic_python_version.py and not router and not assistants and not langfuse and not caching and not cache" -n 4
python -m pytest -vv tests/local_testing --cov=litellm --cov-report=xml -x --junitxml=test-results/junit.xml --durations=5 -k "not test_python_38.py and not router and not assistants and not langfuse and not caching and not cache" -n 4
no_output_timeout: 120m
- run:
name: Rename the coverage files
@ -895,7 +895,6 @@ jobs:
pip install "pytest-retry==1.6.3"
pip install "pytest-asyncio==0.21.1"
pip install "pytest-cov==5.0.0"
pip install "tomli==2.2.1"
- run:
name: Run tests
command: |

View file

@ -358,7 +358,7 @@ poetry install -E extra_proxy -E proxy
Step 3: Test your change:
```
cd tests # pwd: Documents/litellm/litellm/tests
cd litellm/tests # pwd: Documents/litellm/litellm/tests
poetry run flake8
poetry run pytest .
```

Binary file not shown.

View file

@ -72,20 +72,6 @@ general_settings:
prefix_for_stored_virtual_keys: "litellm/" # OPTIONAL. If set, this prefix will be used for stored virtual keys in the secret manager
access_mode: "write_only" # Literal["read_only", "write_only", "read_and_write"]
```
</TabItem>
<TabItem value="read_and_write" label="Read + Write Keys with AWS Secret Manager">
```yaml
general_settings:
master_key: os.environ/litellm_master_key
key_management_system: "aws_secret_manager" # 👈 KEY CHANGE
key_management_settings:
store_virtual_keys: true # OPTIONAL. Defaults to False, when True will store virtual keys in secret manager
prefix_for_stored_virtual_keys: "litellm/" # OPTIONAL. If set, this prefix will be used for stored virtual keys in the secret manager
access_mode: "read_and_write" # Literal["read_only", "write_only", "read_and_write"]
hosted_keys: ["litellm_master_key"] # OPTIONAL. Specify which env keys you stored on AWS
```
</TabItem>
</Tabs>
@ -200,6 +186,34 @@ LiteLLM stores secret under the `prefix_for_stored_virtual_keys` path (default:
## Azure Key Vault
<!--
### Quick Start
```python
### Instantiate Azure Key Vault Client ###
from azure.keyvault.secrets import SecretClient
from azure.identity import ClientSecretCredential
# Set your Azure Key Vault URI
KVUri = os.getenv("AZURE_KEY_VAULT_URI")
# Set your Azure AD application/client ID, client secret, and tenant ID - create an application with permission to call your key vault
client_id = os.getenv("AZURE_CLIENT_ID")
client_secret = os.getenv("AZURE_CLIENT_SECRET")
tenant_id = os.getenv("AZURE_TENANT_ID")
# Initialize the ClientSecretCredential
credential = ClientSecretCredential(client_id=client_id, client_secret=client_secret, tenant_id=tenant_id)
# Create the SecretClient using the credential
client = SecretClient(vault_url=KVUri, credential=credential)
### Connect to LiteLLM ###
import litellm
litellm.secret_manager = client
litellm.get_secret("your-test-key")
``` -->
#### Usage with LiteLLM Proxy Server

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2097,13 +2097,12 @@ class TeamMemberDeleteRequest(MemberDeleteRequest):
class TeamMemberUpdateRequest(TeamMemberDeleteRequest):
max_budget_in_team: Optional[float] = None
role: Optional[Literal["admin", "user"]] = None
max_budget_in_team: float
class TeamMemberUpdateResponse(MemberUpdateResponse):
team_id: str
max_budget_in_team: Optional[float] = None
max_budget_in_team: float
# Organization Member Requests

View file

@ -920,7 +920,7 @@ async def team_member_update(
"""
[BETA]
Update team member budgets and team member role
Update team member budgets
"""
from litellm.proxy.proxy_server import prisma_client
@ -970,8 +970,6 @@ async def team_member_update(
user_api_key_dict=user_api_key_dict,
)
team_table = returned_team_info["team_info"]
## get user id
received_user_id: Optional[str] = None
if data.user_id is not None:
@ -997,50 +995,26 @@ async def team_member_update(
break
### upsert new budget
if data.max_budget_in_team is not None:
if identified_budget_id is None:
new_budget = await prisma_client.db.litellm_budgettable.create(
data={
"max_budget": data.max_budget_in_team,
"created_by": user_api_key_dict.user_id or "",
"updated_by": user_api_key_dict.user_id or "",
}
)
if identified_budget_id is None:
new_budget = await prisma_client.db.litellm_budgettable.create(
data={
"max_budget": data.max_budget_in_team,
"created_by": user_api_key_dict.user_id or "",
"updated_by": user_api_key_dict.user_id or "",
}
)
await prisma_client.db.litellm_teammembership.create(
data={
"team_id": data.team_id,
"user_id": received_user_id,
"budget_id": new_budget.budget_id,
},
)
elif identified_budget_id is not None:
await prisma_client.db.litellm_budgettable.update(
where={"budget_id": identified_budget_id},
data={"max_budget": data.max_budget_in_team},
)
### update team member role
if data.role is not None:
team_members: List[Member] = []
for member in team_table.members_with_roles:
if member.user_id == received_user_id:
team_members.append(
Member(
user_id=member.user_id,
role=data.role,
user_email=data.user_email or member.user_email,
)
)
else:
team_members.append(member)
team_table.members_with_roles = team_members
_db_team_members: List[dict] = [m.model_dump() for m in team_members]
await prisma_client.db.litellm_teamtable.update(
where={"team_id": data.team_id},
data={"members_with_roles": json.dumps(_db_team_members)}, # type: ignore
await prisma_client.db.litellm_teammembership.create(
data={
"team_id": data.team_id,
"user_id": received_user_id,
"budget_id": new_budget.budget_id,
},
)
else:
await prisma_client.db.litellm_budgettable.update(
where={"budget_id": identified_budget_id},
data={"max_budget": data.max_budget_in_team},
)
return TeamMemberUpdateResponse(

View file

@ -37,51 +37,6 @@ def test_litellm_proxy_server():
assert True
def test_package_dependencies():
try:
import tomli
import pathlib
import litellm
# Get the litellm package root path
litellm_path = pathlib.Path(litellm.__file__).parent.parent
pyproject_path = litellm_path / "pyproject.toml"
# Read and parse pyproject.toml
with open(pyproject_path, "rb") as f:
pyproject = tomli.load(f)
# Get all optional dependencies from poetry.dependencies
poetry_deps = pyproject["tool"]["poetry"]["dependencies"]
optional_deps = {
name.lower()
for name, value in poetry_deps.items()
if isinstance(value, dict) and value.get("optional", False)
}
print(optional_deps)
# Get all packages listed in extras
extras = pyproject["tool"]["poetry"]["extras"]
all_extra_deps = set()
for extra_group in extras.values():
all_extra_deps.update(dep.lower() for dep in extra_group)
print(all_extra_deps)
# Check that all optional dependencies are in some extras group
missing_from_extras = optional_deps - all_extra_deps
assert (
not missing_from_extras
), f"Optional dependencies missing from extras: {missing_from_extras}"
print(
f"All {len(optional_deps)} optional dependencies are correctly specified in extras"
)
except Exception as e:
pytest.fail(
f"Error occurred while checking dependencies: {str(e)}\n"
+ traceback.format_exc()
)
import os
import subprocess
import time

View file

@ -2321,47 +2321,6 @@ export const teamMemberAddCall = async (
}
};
export const teamMemberUpdateCall = async (
accessToken: string,
teamId: string,
formValues: Member // Assuming formValues is an object
) => {
try {
console.log("Form Values in teamMemberAddCall:", formValues); // Log the form values before making the API call
const url = proxyBaseUrl
? `${proxyBaseUrl}/team/member_update`
: `/team/member_update`;
const response = await fetch(url, {
method: "POST",
headers: {
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
team_id: teamId,
role: formValues.role,
user_id: formValues.user_id,
}),
});
if (!response.ok) {
const errorData = await response.text();
handleError(errorData);
console.error("Error response from the server:", errorData);
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log("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 organizationMemberAddCall = async (
accessToken: string,
organizationId: string,

View file

@ -2,7 +2,6 @@ import React, { useState, useEffect } from "react";
import Link from "next/link";
import { Typography } from "antd";
import { teamDeleteCall, teamUpdateCall, teamInfoCall } from "./networking";
import TeamMemberModal, { TeamMember } from "@/components/team/edit_membership";
import {
InformationCircleIcon,
PencilAltIcon,
@ -66,12 +65,12 @@ interface EditTeamModalProps {
import {
teamCreateCall,
teamMemberAddCall,
teamMemberUpdateCall,
Member,
modelAvailableCall,
teamListCall
} from "./networking";
const Team: React.FC<TeamProps> = ({
teams,
searchParams,
@ -113,12 +112,11 @@ const Team: React.FC<TeamProps> = ({
const [isTeamModalVisible, setIsTeamModalVisible] = useState(false);
const [isAddMemberModalVisible, setIsAddMemberModalVisible] = useState(false);
const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false);
const [userModels, setUserModels] = useState([]);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [teamToDelete, setTeamToDelete] = useState<string | null>(null);
const [selectedEditMember, setSelectedEditMember] = useState<null | TeamMember>(null);
// store team info as {"team_id": team_info_object}
const [perTeamInfo, setPerTeamInfo] = useState<Record<string, any>>({});
const EditTeamModal: React.FC<EditTeamModalProps> = ({
@ -259,19 +257,16 @@ const Team: React.FC<TeamProps> = ({
const handleMemberOk = () => {
setIsAddMemberModalVisible(false);
setIsEditMemberModalVisible(false);
memberForm.resetFields();
};
const handleCancel = () => {
setIsTeamModalVisible(false);
form.resetFields();
};
const handleMemberCancel = () => {
setIsAddMemberModalVisible(false);
setIsEditMemberModalVisible(false);
memberForm.resetFields();
};
@ -417,7 +412,7 @@ const Team: React.FC<TeamProps> = ({
return false;
}
const _common_member_update_call = async (formValues: Record<string, any>, callType: "add" | "edit") => {
const handleMemberCreate = async (formValues: Record<string, any>) => {
try {
if (accessToken != null && teams != null) {
message.info("Adding Member");
@ -426,27 +421,13 @@ const Team: React.FC<TeamProps> = ({
user_email: formValues.user_email,
user_id: formValues.user_id,
};
let response: any;
if (callType == "add") {
response = await teamMemberAddCall(
accessToken,
selectedTeam["team_id"],
user_role
);
message.success("Member added");
} else {
response = await teamMemberUpdateCall(
accessToken,
selectedTeam["team_id"],
{
"role": formValues.role,
"user_id": formValues.id,
"user_email": formValues.email
}
);
message.success("Member updated");
}
const response: any = await teamMemberAddCall(
accessToken,
selectedTeam["team_id"],
user_role
);
message.success("Member added");
console.log(`response for team create call: ${response["data"]}`);
// Checking if the team exists in the list and updating or adding accordingly
const foundIndex = teams.findIndex((team) => {
console.log(
@ -468,15 +449,7 @@ const Team: React.FC<TeamProps> = ({
} catch (error) {
console.error("Error creating the team:", error);
}
}
const handleMemberCreate = async (formValues: Record<string, any>) => {
_common_member_update_call(formValues, "add");
};
const handleMemberUpdate = async (formValues: Record<string, any>) => {
_common_member_update_call(formValues, "edit");
}
return (
<div className="w-full mx-4">
<Grid numItems={1} className="gap-2 p-8 h-[75vh] w-full mt-2">
@ -858,29 +831,6 @@ const Team: React.FC<TeamProps> = ({
: null}
</TableCell>
<TableCell>{member["role"]}</TableCell>
<TableCell>
{userRole == "Admin" ? (
<>
<Icon
icon={PencilAltIcon}
size="sm"
onClick={() => {
setIsEditMemberModalVisible(true);
setSelectedEditMember({
"id": member["user_id"],
"email": member["user_email"],
"role": member["role"]
})
}}
/>
<Icon
onClick={() => {}}
icon={TrashIcon}
size="sm"
/>
</>
) : null}
</TableCell>
</TableRow>
)
)
@ -888,13 +838,6 @@ const Team: React.FC<TeamProps> = ({
</TableBody>
</Table>
</Card>
<TeamMemberModal
visible={isEditMemberModalVisible}
onCancel={handleMemberCancel}
onSubmit={handleMemberUpdate}
initialData={selectedEditMember}
mode="edit"
/>
{selectedTeam && (
<EditTeamModal
visible={editModalVisible}

View file

@ -5,7 +5,6 @@ import {
modelAvailableCall,
getTotalSpendCall,
getProxyUISettings,
teamListCall,
} from "./networking";
import { Grid, Col, Card, Text, Title } from "@tremor/react";
import CreateKey from "./create_key_button";
@ -173,18 +172,6 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
if (cachedUserModels) {
setUserModels(JSON.parse(cachedUserModels));
} else {
const fetchTeams = async () => {
let givenTeams;
if (userRole != "Admin" && userRole != "Admin Viewer") {
givenTeams = await teamListCall(accessToken, userID)
} else {
givenTeams = await teamListCall(accessToken)
}
console.log(`givenTeams: ${givenTeams}`)
setTeams(givenTeams)
}
const fetchData = async () => {
try {
const proxy_settings: ProxySettings = await getProxyUISettings(accessToken);
@ -207,6 +194,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
setUserSpendData(response["user_info"]);
console.log(`userSpendData: ${JSON.stringify(userSpendData)}`)
setKeys(response["keys"]); // Assuming this is the correct path to your data
setTeams(response["teams"]);
const teamsArray = [...response["teams"]];
if (teamsArray.length > 0) {
console.log(`response['teams']: ${teamsArray}`);
@ -247,7 +235,6 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
}
};
fetchData();
fetchTeams();
}
}
}, [userID, token, accessToken, keys, userRole]);

View file

@ -131,57 +131,6 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
const [knownTeamIDs, setKnownTeamIDs] = useState(initialKnownTeamIDs);
// Function to check if user is admin of a team
const isUserTeamAdmin = (team: any) => {
if (!team.members_with_roles) return false;
return team.members_with_roles.some(
(member: any) => member.role === "admin" && member.user_id === userID
);
};
// Combine all keys that user should have access to
const all_keys_to_display = React.useMemo(() => {
let allKeys: any[] = [];
// If no teams, return personal keys
if (!teams || teams.length === 0) {
return data;
}
teams.forEach(team => {
// For default team or when user is not admin, use personal keys (data)
if (team.team_id === "default-team" || !isUserTeamAdmin(team)) {
if (selectedTeam && selectedTeam.team_id === team.team_id && data) {
allKeys = [...allKeys, ...data.filter(key => key.team_id === team.team_id)];
}
}
// For teams where user is admin, use team keys
else if (isUserTeamAdmin(team)) {
if (selectedTeam && selectedTeam.team_id === team.team_id) {
allKeys = [...allKeys, ...(team.keys || [])];
}
}
});
// If no team is selected, show all accessible keys
if (!selectedTeam && data) {
const personalKeys = data.filter(key => !key.team_id || key.team_id === "default-team");
const adminTeamKeys = teams
.filter(team => isUserTeamAdmin(team))
.flatMap(team => team.keys || []);
allKeys = [...personalKeys, ...adminTeamKeys];
}
// Filter out litellm-dashboard keys
allKeys = allKeys.filter(key => key.team_id !== "litellm-dashboard");
// Remove duplicates based on token
const uniqueKeys = Array.from(
new Map(allKeys.map(key => [key.token, key])).values()
);
return uniqueKeys;
}, [data, teams, selectedTeam, userID]);
useEffect(() => {
const calculateNewExpiryTime = (duration: string | undefined) => {
@ -909,7 +858,7 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
</TableRow>
</TableHead>
<TableBody>
{all_keys_to_display && all_keys_to_display.map((item) => {
{data.map((item) => {
console.log(item);
// skip item if item.team_id == "litellm-dashboard"
if (item.team_id === "litellm-dashboard") {