(Improvements) use /openai/ pass through with OpenAI Ruby for Assistants API (#8884)

* add ruby assistants testing

* _join_url_paths

* run ruby tests on ci/cd

* TestBaseOpenAIPassThroughHandler

* _join_url_paths

* fix _join_url_paths

* Install Ruby and Bundler

* Install Ruby and Bundler
This commit is contained in:
Ishaan Jaff 2025-02-27 20:01:16 -08:00 committed by GitHub
parent 378e3d9e4d
commit 51a6a219cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 219 additions and 58 deletions

View file

@ -398,7 +398,7 @@ async def azure_proxy_route(
)
# Add or update query parameters
azure_api_key = passthrough_endpoint_router.get_credentials(
custom_llm_provider="azure",
custom_llm_provider=litellm.LlmProviders.AZURE.value,
region_name=None,
)
if azure_api_key is None:
@ -413,6 +413,7 @@ async def azure_proxy_route(
user_api_key_dict=user_api_key_dict,
base_target_url=base_target_url,
api_key=azure_api_key,
custom_llm_provider=litellm.LlmProviders.AZURE,
)
@ -435,7 +436,7 @@ async def openai_proxy_route(
base_target_url = "https://api.openai.com/"
# Add or update query parameters
openai_api_key = passthrough_endpoint_router.get_credentials(
custom_llm_provider="openai",
custom_llm_provider=litellm.LlmProviders.OPENAI.value,
region_name=None,
)
if openai_api_key is None:
@ -450,6 +451,7 @@ async def openai_proxy_route(
user_api_key_dict=user_api_key_dict,
base_target_url=base_target_url,
api_key=openai_api_key,
custom_llm_provider=litellm.LlmProviders.OPENAI,
)
@ -462,24 +464,19 @@ class BaseOpenAIPassThroughHandler:
user_api_key_dict: UserAPIKeyAuth,
base_target_url: str,
api_key: str,
custom_llm_provider: litellm.LlmProviders,
):
encoded_endpoint = httpx.URL(endpoint).path
# Ensure endpoint starts with '/' for proper URL construction
if not encoded_endpoint.startswith("/"):
encoded_endpoint = "/" + encoded_endpoint
# Ensure base_target_url is properly formatted for OpenAI
base_target_url = (
BaseOpenAIPassThroughHandler._append_v1_to_openai_passthrough_url(
base_target_url
)
)
# Construct the full target URL by properly joining the base URL and endpoint path
base_url = httpx.URL(base_target_url)
updated_url = BaseOpenAIPassThroughHandler._join_url_paths(
base_url, encoded_endpoint
base_url=base_url,
path=encoded_endpoint,
custom_llm_provider=custom_llm_provider,
)
## check for streaming
@ -505,21 +502,15 @@ class BaseOpenAIPassThroughHandler:
return received_value
@staticmethod
def _append_v1_to_openai_passthrough_url(base_url: str) -> str:
"""
Appends the /v1 path to the OpenAI base URL if it's the OpenAI API URL
"""
if base_url.rstrip("/") == "https://api.openai.com":
return "https://api.openai.com/v1"
return base_url
@staticmethod
def _append_openai_beta_header(headers: dict, request: Request) -> dict:
"""
Appends the OpenAI-Beta header to the headers if the request is an OpenAI Assistants API request
"""
if RouteChecks._is_assistants_api_request(request) is True:
if (
RouteChecks._is_assistants_api_request(request) is True
and "OpenAI-Beta" not in headers
):
headers["OpenAI-Beta"] = "assistants=v2"
return headers
@ -535,17 +526,31 @@ class BaseOpenAIPassThroughHandler:
)
@staticmethod
def _join_url_paths(base_url: httpx.URL, path: str) -> httpx.URL:
def _join_url_paths(
base_url: httpx.URL, path: str, custom_llm_provider: litellm.LlmProviders
) -> str:
"""
Properly joins a base URL with a path, preserving any existing path in the base URL.
"""
# Join paths correctly by removing trailing/leading slashes as needed
if not base_url.path or base_url.path == "/":
# If base URL has no path, just use the new path
return base_url.copy_with(path=path)
joined_path_str = str(base_url.copy_with(path=path))
else:
# Otherwise, combine the paths
base_path = base_url.path.rstrip("/")
clean_path = path.lstrip("/")
full_path = f"{base_path}/{clean_path}"
joined_path_str = str(base_url.copy_with(path=full_path))
# Join paths correctly by removing trailing/leading slashes as needed
base_path = base_url.path.rstrip("/")
clean_path = path.lstrip("/")
full_path = f"{base_path}/{clean_path}"
# Apply OpenAI-specific path handling for both branches
if (
custom_llm_provider == litellm.LlmProviders.OPENAI
and "/v1/" not in joined_path_str
):
# Insert v1 after api.openai.com for OpenAI requests
joined_path_str = joined_path_str.replace(
"api.openai.com/", "api.openai.com/v1/"
)
return base_url.copy_with(path=full_path)
return joined_path_str