From a609139dded26b5f59dc55dd68ad0baa470b6e53 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Thu, 23 Jan 2025 15:31:16 -0800 Subject: [PATCH] Revert "Litellm dev 01 10 2025 p2 (#7679)" This reverts commit c4780479a990f532083bdf1e9fa88750eff00098. --- .circleci/config.yml | 3 +- README.md | 2 +- dist/litellm-1.57.6.tar.gz | Bin 64 -> 0 bytes docs/my-website/docs/secret.md | 42 ++++++---- litellm/proxy/_experimental/out/404.html | 1 + .../proxy/_experimental/out/model_hub.html | 1 + .../proxy/_experimental/out/onboarding.html | 1 + litellm/proxy/_types.py | 5 +- .../management_endpoints/team_endpoints.py | 66 +++++---------- .../test_basic_python_version.py | 45 ---------- .../src/components/networking.tsx | 41 ---------- ui/litellm-dashboard/src/components/teams.tsx | 77 +++--------------- .../src/components/user_dashboard.tsx | 15 +--- .../src/components/view_key_table.tsx | 53 +----------- 14 files changed, 67 insertions(+), 285 deletions(-) delete mode 100644 dist/litellm-1.57.6.tar.gz create mode 100644 litellm/proxy/_experimental/out/404.html create mode 100644 litellm/proxy/_experimental/out/model_hub.html create mode 100644 litellm/proxy/_experimental/out/onboarding.html diff --git a/.circleci/config.yml b/.circleci/config.yml index acf8612eacd..2ee3f24a08d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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: | diff --git a/README.md b/README.md index c7ea44cf462..b1e6c9db384 100644 --- a/README.md +++ b/README.md @@ -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 . ``` diff --git a/dist/litellm-1.57.6.tar.gz b/dist/litellm-1.57.6.tar.gz deleted file mode 100644 index 01a039cf6eeaf66098473f96bea25fad31613393..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmb2|=HOre0;c~tnI)+?Ik~!qdZy-jW_l%wMGS8bGV%iD4lVfZpUY>y0Hh8K8qAqz M-IG;k&|qKy03*o{)Bpeg diff --git a/docs/my-website/docs/secret.md b/docs/my-website/docs/secret.md index a65c696f367..22bad6fec18 100644 --- a/docs/my-website/docs/secret.md +++ b/docs/my-website/docs/secret.md @@ -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"] ``` - - - -```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 -``` - @@ -200,6 +186,34 @@ LiteLLM stores secret under the `prefix_for_stored_virtual_keys` path (default: ## Azure Key Vault + #### Usage with LiteLLM Proxy Server diff --git a/litellm/proxy/_experimental/out/404.html b/litellm/proxy/_experimental/out/404.html new file mode 100644 index 00000000000..3bbcc888404 --- /dev/null +++ b/litellm/proxy/_experimental/out/404.html @@ -0,0 +1 @@ +404: This page could not be found.LiteLLM Dashboard

404

This page could not be found.

\ No newline at end of file diff --git a/litellm/proxy/_experimental/out/model_hub.html b/litellm/proxy/_experimental/out/model_hub.html new file mode 100644 index 00000000000..8a63b4419fa --- /dev/null +++ b/litellm/proxy/_experimental/out/model_hub.html @@ -0,0 +1 @@ +LiteLLM Dashboard \ No newline at end of file diff --git a/litellm/proxy/_experimental/out/onboarding.html b/litellm/proxy/_experimental/out/onboarding.html new file mode 100644 index 00000000000..070f19d8e3f --- /dev/null +++ b/litellm/proxy/_experimental/out/onboarding.html @@ -0,0 +1 @@ +LiteLLM Dashboard \ No newline at end of file diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 3461952ed6d..bad7c6c1178 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -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 diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 6ebfed0eef1..1d21e315b37 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -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( diff --git a/tests/local_testing/test_basic_python_version.py b/tests/local_testing/test_basic_python_version.py index c629ef3df8e..5fa48f09699 100644 --- a/tests/local_testing/test_basic_python_version.py +++ b/tests/local_testing/test_basic_python_version.py @@ -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 diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index f219b563f9a..a0ed6d702a6 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -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, diff --git a/ui/litellm-dashboard/src/components/teams.tsx b/ui/litellm-dashboard/src/components/teams.tsx index e988b65e3a7..8979a96a3b4 100644 --- a/ui/litellm-dashboard/src/components/teams.tsx +++ b/ui/litellm-dashboard/src/components/teams.tsx @@ -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 = ({ teams, searchParams, @@ -113,12 +112,11 @@ const Team: React.FC = ({ 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(null); - const [selectedEditMember, setSelectedEditMember] = useState(null); + // store team info as {"team_id": team_info_object} const [perTeamInfo, setPerTeamInfo] = useState>({}); const EditTeamModal: React.FC = ({ @@ -259,19 +257,16 @@ const Team: React.FC = ({ 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 = ({ return false; } - const _common_member_update_call = async (formValues: Record, callType: "add" | "edit") => { + const handleMemberCreate = async (formValues: Record) => { try { if (accessToken != null && teams != null) { message.info("Adding Member"); @@ -426,27 +421,13 @@ const Team: React.FC = ({ 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 = ({ } catch (error) { console.error("Error creating the team:", error); } - } - - const handleMemberCreate = async (formValues: Record) => { - _common_member_update_call(formValues, "add"); }; - - const handleMemberUpdate = async (formValues: Record) => { - _common_member_update_call(formValues, "edit"); - } return (
@@ -858,29 +831,6 @@ const Team: React.FC = ({ : null} {member["role"]} - - {userRole == "Admin" ? ( - <> - { - setIsEditMemberModalVisible(true); - setSelectedEditMember({ - "id": member["user_id"], - "email": member["user_email"], - "role": member["role"] - }) - }} - /> - {}} - icon={TrashIcon} - size="sm" - /> - - ) : null} - ) ) @@ -888,13 +838,6 @@ const Team: React.FC = ({ - {selectedTeam && ( = ({ 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 = ({ 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 = ({ } }; fetchData(); - fetchTeams(); } } }, [userID, token, accessToken, keys, userRole]); diff --git a/ui/litellm-dashboard/src/components/view_key_table.tsx b/ui/litellm-dashboard/src/components/view_key_table.tsx index 144c30c0d20..5ee3007195c 100644 --- a/ui/litellm-dashboard/src/components/view_key_table.tsx +++ b/ui/litellm-dashboard/src/components/view_key_table.tsx @@ -131,57 +131,6 @@ const ViewKeyTable: React.FC = ({ 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 = ({ - {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") {