perf(proxy): lazy-load provider passthrough routes (#40691)

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
devin-ai-integration[bot] 2026-09-11 09:48:53 -07:00 committed by GitHub
parent 67cb34ceee
commit 729ea6b832
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 5317 additions and 394 deletions

View file

@ -8,11 +8,13 @@ omits each feature's routes until the feature is warmed.
import asyncio
import importlib
from collections.abc import Callable
from collections.abc import Callable, Mapping, Sequence
from collections.abc import Set as AbstractSet
from dataclasses import dataclass, field
from types import MappingProxyType
from typing import TYPE_CHECKING, Final
from starlette.routing import BaseRoute, Match
from starlette.types import Receive, Scope, Send
from litellm._logging import verbose_proxy_logger
@ -185,6 +187,31 @@ LAZY_FEATURES: Final[tuple[LazyFeature, ...]] = (
module_path="litellm.proxy.management_endpoints.config_override_endpoints",
path_prefixes=("/config_overrides",),
),
LazyFeature(
name="llm_passthrough",
module_path="litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints",
path_prefixes=(
"/anthropic/",
"/assemblyai/",
"/azure/",
"/azure_ai/",
"/bedrock/",
"/cohere/",
"/comprehendmedical",
"/cursor/",
"/eu.assemblyai/",
"/gemini/",
"/gigachat/",
"/milvus/",
"/mistral/",
"/openai/",
"/openai_passthrough/",
"/vertex-ai/",
"/vertex_ai/",
"/vllm/",
"/watsonx/",
),
),
LazyFeature(
name="realtime",
module_path="litellm.proxy.realtime_endpoints.endpoints",
@ -308,14 +335,64 @@ class LazyFeatureMiddleware:
if root_path and path.startswith(root_path + "/"):
path = path[len(root_path) :] # rebind-ok: local strip after the boundary check above
for feat in self._features:
if feat.module_path in self._loaded:
if feat.module_path in self._loaded or not feat.matches(path):
continue
if feat.matches(path):
await _force_load(self._fastapi_app, feat)
if _eager_route_wins(self._fastapi_app, feat, scope):
continue
await _force_load(self._fastapi_app, feat, self._features)
await self.app(scope, receive, send)
async def _force_load(app: "FastAPI", feat: LazyFeature) -> bool:
def _lazy_slots(app: "FastAPI") -> Mapping[str, int]:
return app.state.lazy_slots if hasattr(app.state, "lazy_slots") else MappingProxyType({})
def reserve_lazy_slot(app: "FastAPI", name: str, features: tuple[LazyFeature, ...] = LAZY_FEATURES) -> None:
"""Record the table position the feature's router used to be included at, so its
routes are spliced back in there once it loads and keep the same precedence."""
feat: Final = next(f for f in features if f.name == name)
app.state.lazy_slots = MappingProxyType({**_lazy_slots(app), feat.module_path: len(app.router.routes)})
def _eager_route_wins(app: "FastAPI", feat: LazyFeature, scope: Scope) -> bool:
"""Routes ahead of a feature's reserved slot beat its routes in Starlette's scan,
so a request one of them fully matches never needs the feature loaded."""
slot: Final = _lazy_slots(app).get(feat.module_path)
if slot is None:
return False
return any(route.matches(scope)[0] is Match.FULL for route in app.router.routes[:slot])
def _in_registry_order(
routes: Sequence[BaseRoute],
lazy_routes: Mapping[str, tuple[BaseRoute, ...]],
features: tuple[LazyFeature, ...],
slots: Mapping[str, int],
) -> tuple[BaseRoute, ...]:
"""Lazy routers land in registry order, not first-request order, so overlapping
paths (/openai/{endpoint:path} vs /openai/v1/realtime/calls) resolve the same
way no matter which feature a deployment happens to hit first. Features with a
reserved slot go back where they were eagerly included; the rest follow every
eager route."""
rank: Final = MappingProxyType({f.module_path: i for i, f in enumerate(features)})
modules: Final = tuple(sorted(lazy_routes, key=lambda m: rank.get(m, len(rank))))
lazy_ids: Final = frozenset(id(route) for module_path in modules for route in lazy_routes[module_path])
eager: Final = tuple(route for route in routes if id(route) not in lazy_ids)
def slot_of(module_path: str) -> int:
return min(slots.get(module_path, len(eager)), len(eager))
return tuple(
route
for index in range(len(eager) + 1)
for route in (
*(r for module_path in modules if slot_of(module_path) == index for r in lazy_routes[module_path]),
*eager[index : index + 1],
)
)
async def _force_load(app: "FastAPI", feat: LazyFeature, features: tuple[LazyFeature, ...] = LAZY_FEATURES) -> bool:
"""Import + register a lazy feature exactly once per (app, module).
Shared by the middleware and the /lazy/warm endpoint."""
if not hasattr(app.state, "lazy_loaded"):
@ -330,7 +407,18 @@ async def _force_load(app: "FastAPI", feat: LazyFeature) -> bool:
# mutates app.router.routes, so it stays on the loop thread.
loop: Final = asyncio.get_running_loop()
module: Final = await loop.run_in_executor(None, importlib.import_module, feat.module_path)
before: Final = len(app.router.routes)
feat.register_fn(app, module)
previous: Final[Mapping[str, tuple[BaseRoute, ...]]] = (
app.state.lazy_routes if hasattr(app.state, "lazy_routes") else MappingProxyType({})
)
lazy_routes: Final[Mapping[str, tuple[BaseRoute, ...]]] = MappingProxyType(
{**previous, feat.module_path: tuple(app.router.routes[before:])}
)
app.state.lazy_routes = lazy_routes # rebind-ok: the app owns the record of which routes each feature added
app.router.routes[:] = _in_registry_order( # rebind-ok: the app owns its route table
app.router.routes, lazy_routes, features, _lazy_slots(app)
)
app.state.lazy_loaded.add(feat.module_path)
app.openapi_schema = None
verbose_proxy_logger.info(

File diff suppressed because it is too large Load diff

View file

@ -97,7 +97,6 @@ else:
vertex_llm_base: Final = VertexBase()
router: Final = APIRouter()
openai_passthrough_router: Final = APIRouter()
default_vertex_config: Final = None
passthrough_endpoint_router: Final = PassthroughEndpointRouter()
@ -2297,11 +2296,6 @@ async def vertex_proxy_route(
)
@openai_passthrough_router.api_route(
"/openai_passthrough/{endpoint:path}",
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
tags=["OpenAI Pass-through", "pass-through"],
)
@router.api_route(
"/openai/{endpoint:path}",
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],

View file

@ -0,0 +1,44 @@
"""/openai_passthrough must be matched ahead of the native /{provider}/v1/files and
/{provider}/v1/batches routes, so unlike the other provider passthrough routes it is
registered at startup and defers to the lazily loaded handler per call."""
from typing import Final
from fastapi import APIRouter, Depends, Request, Response
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
router: Final = APIRouter()
@router.api_route(
"/openai_passthrough/{endpoint:path}",
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
tags=["OpenAI Pass-through", "pass-through"],
)
async def openai_passthrough_route(
endpoint: str,
request: Request,
fastapi_response: Response,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
) -> Response:
"""
Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
implementations (e.g. the Responses API at /v1/responses).
Examples:
- /openai_passthrough/v1/responses
- /openai_passthrough/v1/responses/{response_id}
- /openai_passthrough/v1/responses/{response_id}/input_items
[Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
"""
from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import openai_proxy_route
return await openai_proxy_route(
endpoint=endpoint,
request=request,
fastapi_response=fastapi_response,
user_api_key_dict=user_api_key_dict,
)

View file

@ -304,7 +304,7 @@ from litellm.litellm_core_utils.sensitive_data_masker import (
)
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler
from litellm.llms.vertex_ai.vertex_llm_base import VertexBase
from litellm.proxy._lazy_features import attach_lazy_features
from litellm.proxy._lazy_features import attach_lazy_features, reserve_lazy_slot
from litellm.proxy._types import *
from litellm.proxy.analytics_endpoints.analytics_endpoints import (
router as analytics_router,
@ -639,13 +639,8 @@ from litellm.proxy.openai_files_endpoints.files_endpoints import (
from litellm.proxy.openai_files_endpoints.files_endpoints import (
set_files_config,
)
from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
openai_passthrough_router,
passthrough_endpoint_router,
vertex_ai_live_websocket_passthrough,
)
from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
router as llm_passthrough_router,
from litellm.proxy.pass_through_endpoints.openai_passthrough_endpoints import (
router as openai_passthrough_router,
)
from litellm.proxy.pass_through_endpoints.pass_through_endpoints import (
initialize_pass_through_endpoints,
@ -6047,6 +6042,10 @@ class ProxyConfig:
set_files_config(config=files_config)
## default config for vertex ai routes
from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
passthrough_endpoint_router,
)
default_vertex_config: Final = config.get("default_vertex_config", None)
passthrough_endpoint_router.set_default_vertex_config(config=default_vertex_config)
@ -11763,6 +11762,10 @@ async def vertex_ai_live_passthrough_endpoint(
This endpoint delegates to the WebSocket function defined in llm_passthrough_endpoints.py
"""
from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
vertex_ai_live_websocket_passthrough,
)
return await vertex_ai_live_websocket_passthrough(
websocket=websocket,
model=model,
@ -18668,7 +18671,7 @@ app.include_router(credential_router)
app.include_router(openai_passthrough_router)
app.include_router(batches_router)
app.include_router(openai_files_router)
app.include_router(llm_passthrough_router)
reserve_lazy_slot(app, "llm_passthrough")
app.include_router(pass_through_router)
app.include_router(health_router)
app.include_router(key_management_router)

View file

@ -4,7 +4,7 @@ import contextlib
import json
import os
import traceback
from collections.abc import Mapping
from collections.abc import Iterator, Mapping
from types import MappingProxyType, SimpleNamespace
from typing import Final
from unittest import mock
@ -12,7 +12,9 @@ from unittest.mock import AsyncMock, MagicMock, Mock, patch
import httpx
import pytest
import respx
from fastapi import HTTPException, Request, Response
from fastapi.routing import APIRoute
from fastapi.responses import StreamingResponse
from fastapi.testclient import TestClient
from starlette.datastructures import FormData
@ -45,6 +47,7 @@ from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
)
from litellm.proxy._types import LitellmUserRoles, SpecialHeaders, UserAPIKeyAuth
from litellm.proxy.auth.handle_jwt import JWTHandler
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.types.passthrough_endpoints.vertex_ai import VertexPassThroughCredentials
@ -3339,8 +3342,11 @@ class TestOpenAIPassthroughRoute:
def _resolve_route_name(method: str, path: str) -> str | None:
from starlette.routing import Match
from litellm.proxy._lazy_features import LAZY_FEATURES, _force_load
from litellm.proxy.proxy_server import app
asyncio.run(_force_load(app, next(f for f in LAZY_FEATURES if f.name == "llm_passthrough")))
scope: Final = {
"type": "http",
"method": method,
@ -3350,8 +3356,8 @@ def _resolve_route_name(method: str, path: str) -> str | None:
"root_path": "",
}
for route in app.router.routes:
if route.matches(scope)[0] == Match.FULL:
return getattr(route, "name", None)
if isinstance(route, APIRoute) and route.matches(scope)[0] == Match.FULL:
return route.name
return None
@ -3376,7 +3382,7 @@ def test_openai_passthrough_prefix_wins_over_native_provider_routes(method, path
/{provider}/v1/files and /{provider}/v1/batches routes must never capture it
with provider="openai_passthrough" (which 500s on the LlmProviders lookup).
"""
assert _resolve_route_name(method, path) == "openai_proxy_route"
assert _resolve_route_name(method, path) == "openai_passthrough_route"
@pytest.mark.parametrize(
@ -3393,6 +3399,41 @@ def test_native_provider_routes_are_unchanged(method, path, expected_name):
assert _resolve_route_name(method, path) == expected_name
@pytest.fixture
def openai_passthrough_client(monkeypatch: pytest.MonkeyPatch) -> Iterator[TestClient]:
from litellm.proxy.proxy_server import app
monkeypatch.setenv("OPENAI_API_KEY", "sk-upstream")
monkeypatch.delenv("SERVER_ROOT_PATH", raising=False)
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
litellm.in_memory_llm_clients_cache.flush_cache()
monkeypatch.setitem(app.dependency_overrides, user_api_key_auth, lambda: UserAPIKeyAuth(api_key="sk-virtual"))
yield TestClient(app)
@pytest.mark.parametrize(
"method, path, body",
[
("POST", "/v1/responses", {"model": "gpt-5.1", "input": "hi"}),
("GET", "/v1/files", None),
("POST", "/v1/batches", {"input_file_id": "file-abc123", "endpoint": "/v1/responses"}),
],
)
def test_openai_passthrough_forwards_verbatim_to_openai(
openai_passthrough_client: TestClient, method: str, path: str, body: dict[str, str] | None
) -> None:
"""Every /openai_passthrough request, including the /v1/files and /v1/batches
paths that native provider routes also claim, must reach OpenAI unchanged."""
with respx.mock(assert_all_called=True) as upstream:
route = upstream.request(method, f"https://api.openai.com{path}").mock(
return_value=httpx.Response(200, json={"id": "upstream_123"})
)
response = openai_passthrough_client.request(method, f"/openai_passthrough{path}", json=body)
assert (response.status_code, response.json()) == (200, {"id": "upstream_123"})
assert route.calls.last.request.headers["authorization"] == "Bearer sk-upstream"
class TestCursorProxyRoute:
"""Tests for the Cursor Cloud Agents pass-through route."""

View file

@ -9183,6 +9183,126 @@ class TestLazyFeaturesNotImportedAtStartup:
class TestLazyFeatureMiddleware:
"""Behavior of the middleware itself, exercised in isolation."""
@pytest.mark.asyncio
async def test_llm_passthrough_loads_on_first_provider_request(self, monkeypatch):
"""An app that never registered the provider passthrough routes 404s a
provider request; behind the middleware the same request registers the
routes and is forwarded to the provider with the configured key."""
import respx
from fastapi import FastAPI
from litellm.proxy._lazy_features import LAZY_FEATURES, LazyFeatureMiddleware
monkeypatch.setenv("MISTRAL_API_KEY", "sk-upstream")
monkeypatch.delenv("SERVER_ROOT_PATH", raising=False)
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
litellm.in_memory_llm_clients_cache.flush_cache()
feat = next(f for f in LAZY_FEATURES if f.name == "llm_passthrough")
target_app = FastAPI()
target_app.dependency_overrides[user_api_key_auth] = lambda: UserAPIKeyAuth(api_key="sk-virtual")
mw = LazyFeatureMiddleware(target_app, fastapi_app=target_app, features=(feat,))
with respx.mock() as upstream:
route = upstream.get("https://api.mistral.ai/v1/models").mock(
return_value=httpx.Response(200, json={"object": "list", "data": []})
)
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=target_app), base_url="http://t") as bare:
assert (await bare.get("/mistral/v1/models")).status_code == 404
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=mw), base_url="http://t") as lazy:
response = await lazy.get("/mistral/v1/models")
assert (response.status_code, response.json()) == (200, {"object": "list", "data": []})
assert route.calls.last.request.headers["authorization"] == "Bearer sk-upstream"
def test_llm_passthrough_prefixes_cover_every_route_the_module_registers(self):
"""A route the module registers under a prefix the feature does not claim
would 404 until an unrelated provider request happens to load the module."""
from litellm.proxy._lazy_features import LAZY_FEATURES
feat = next(f for f in LAZY_FEATURES if f.name == "llm_passthrough")
paths = [r.path for r in importlib.import_module(feat.module_path).router.routes]
assert {"/mistral/{endpoint:path}", "/openai/{endpoint:path}"} <= set(paths)
unreachable = [p for p in paths if not feat.matches(p.replace("{endpoint:path}", "x"))]
assert unreachable == [], f"routes the middleware would never load: {unreachable}"
@pytest.mark.asyncio
@pytest.mark.parametrize("first_hit", ["/v1/realtime/calls", "/openai/v1/models"])
async def test_lazy_routes_land_in_registry_order_not_first_hit_order(self, first_hit):
"""Two lazy features with overlapping paths must answer a request with the
same handler no matter which one a deployment happens to hit first."""
from fastapi import APIRouter, FastAPI
from litellm.proxy._lazy_features import LazyFeature, LazyFeatureMiddleware
def make_register(path, handler):
def register(app, module):
router = APIRouter()
router.add_api_route(path, lambda: {"handler": handler}, methods=["POST"])
app.include_router(router)
return register
catch_all = LazyFeature(
name="catch_all",
module_path="json",
path_prefixes=("/openai/",),
register_fn=make_register("/openai/{endpoint:path}", "catch_all"),
)
specific = LazyFeature(
name="specific",
module_path="base64",
path_prefixes=("/openai/v1/realtime", "/v1/realtime"),
register_fn=make_register("/openai/v1/realtime/calls", "specific"),
)
target_app = FastAPI()
mw = LazyFeatureMiddleware(target_app, fastapi_app=target_app, features=(catch_all, specific))
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=mw), base_url="http://t") as client:
await client.post(first_hit)
await client.post("/openai/v1/models")
response = await client.post("/openai/v1/realtime/calls")
assert response.json() == {"handler": "catch_all"}
@pytest.mark.asyncio
@pytest.mark.parametrize("root_path", ["", "/api"])
async def test_reserved_slot_keeps_lazy_catch_all_ahead_of_later_eager_routes(self, root_path):
"""/{mcp_server_name}/mcp is registered after the provider passthrough router
at startup, so /mistral/mcp must keep reaching the provider catch-all once
that router loads lazily instead of being swallowed by the MCP route. The
native /mistral/v1/files route sits ahead of it, so that path neither loads
the feature nor changes owner, with or without a SERVER_ROOT_PATH prefix."""
from fastapi import APIRouter, FastAPI
from litellm.proxy._lazy_features import LazyFeature, LazyFeatureMiddleware, reserve_lazy_slot
def register(app, module):
router = APIRouter()
router.add_api_route("/mistral/{endpoint:path}", lambda: {"handler": "passthrough"}, methods=["POST"])
app.include_router(router)
passthrough = LazyFeature(
name="llm_passthrough", module_path="json", path_prefixes=("/mistral/",), register_fn=register
)
target_app = FastAPI(root_path=root_path)
target_app.add_api_route("/mistral/v1/files", lambda: {"handler": "files"}, methods=["POST"])
reserve_lazy_slot(target_app, "llm_passthrough", features=(passthrough,))
target_app.add_api_route("/{mcp_server_name}/mcp", lambda: {"handler": "mcp"}, methods=["POST"])
target_app.add_middleware(LazyFeatureMiddleware, fastapi_app=target_app, features=(passthrough,))
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=target_app), base_url="http://t") as client:
files_first = (await client.post(f"{root_path}/mistral/v1/files")).json()["handler"]
loaded_after_files = frozenset(target_app.state.lazy_loaded)
handlers = [
(await client.post(f"{root_path}{path}")).json()["handler"]
for path in ("/mistral/mcp", "/mistral/v1/files")
]
assert (files_first, loaded_after_files) == ("files", frozenset())
assert handlers == ["passthrough", "files"]
@pytest.mark.asyncio
async def test_first_request_triggers_load_subsequent_does_not(self):
from fastapi import FastAPI

View file

@ -9547,26 +9547,6 @@ export interface paths {
patch?: never;
trace?: never;
};
"/openai/": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* WebSocket: openai_websocket_proxy_route
* @description WebSocket connection endpoint
*/
get: operations["websocket_openai_websocket_proxy_route_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/openai/deployments/{model}/chat/completions": {
parameters: {
query?: never;
@ -10122,26 +10102,6 @@ export interface paths {
patch: operations["openai_proxy_route_openai__endpoint__patch"];
trace?: never;
};
"/openai_passthrough/": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* WebSocket: openai_websocket_proxy_route
* @description WebSocket connection endpoint
*/
get: operations["websocket_openai_websocket_proxy_route_get_2"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/openai_passthrough/{endpoint}": {
parameters: {
query?: never;
@ -10150,132 +10110,72 @@ export interface paths {
cookie?: never;
};
/**
* Openai Proxy Route
* @description Pass-through endpoint for OpenAI API calls.
*
* Available on both routes:
* - /openai/{endpoint:path} - Standard OpenAI passthrough route
* - /openai_passthrough/{endpoint:path} - Dedicated passthrough route (recommended for Responses API)
*
* Use /openai_passthrough/* when you need guaranteed passthrough to OpenAI without conflicts
* with LiteLLM's native implementations (e.g., for the Responses API at /v1/responses).
* Openai Passthrough Route
* @description Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
* implementations (e.g. the Responses API at /v1/responses).
*
* Examples:
* Standard route:
* - /openai/v1/chat/completions
* - /openai/v1/assistants
* - /openai/v1/threads
*
* Dedicated passthrough (for Responses API):
* - /openai_passthrough/v1/responses
* - /openai_passthrough/v1/responses/{response_id}
* - /openai_passthrough/v1/responses/{response_id}/input_items
*
* [Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
*/
get: operations["openai_proxy_route_openai_passthrough__endpoint__get"];
get: operations["openai_passthrough_route_openai_passthrough__endpoint__get"];
/**
* Openai Proxy Route
* @description Pass-through endpoint for OpenAI API calls.
*
* Available on both routes:
* - /openai/{endpoint:path} - Standard OpenAI passthrough route
* - /openai_passthrough/{endpoint:path} - Dedicated passthrough route (recommended for Responses API)
*
* Use /openai_passthrough/* when you need guaranteed passthrough to OpenAI without conflicts
* with LiteLLM's native implementations (e.g., for the Responses API at /v1/responses).
* Openai Passthrough Route
* @description Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
* implementations (e.g. the Responses API at /v1/responses).
*
* Examples:
* Standard route:
* - /openai/v1/chat/completions
* - /openai/v1/assistants
* - /openai/v1/threads
*
* Dedicated passthrough (for Responses API):
* - /openai_passthrough/v1/responses
* - /openai_passthrough/v1/responses/{response_id}
* - /openai_passthrough/v1/responses/{response_id}/input_items
*
* [Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
*/
put: operations["openai_proxy_route_openai_passthrough__endpoint__put"];
put: operations["openai_passthrough_route_openai_passthrough__endpoint__put"];
/**
* Openai Proxy Route
* @description Pass-through endpoint for OpenAI API calls.
*
* Available on both routes:
* - /openai/{endpoint:path} - Standard OpenAI passthrough route
* - /openai_passthrough/{endpoint:path} - Dedicated passthrough route (recommended for Responses API)
*
* Use /openai_passthrough/* when you need guaranteed passthrough to OpenAI without conflicts
* with LiteLLM's native implementations (e.g., for the Responses API at /v1/responses).
* Openai Passthrough Route
* @description Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
* implementations (e.g. the Responses API at /v1/responses).
*
* Examples:
* Standard route:
* - /openai/v1/chat/completions
* - /openai/v1/assistants
* - /openai/v1/threads
*
* Dedicated passthrough (for Responses API):
* - /openai_passthrough/v1/responses
* - /openai_passthrough/v1/responses/{response_id}
* - /openai_passthrough/v1/responses/{response_id}/input_items
*
* [Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
*/
post: operations["openai_proxy_route_openai_passthrough__endpoint__post"];
post: operations["openai_passthrough_route_openai_passthrough__endpoint__post"];
/**
* Openai Proxy Route
* @description Pass-through endpoint for OpenAI API calls.
*
* Available on both routes:
* - /openai/{endpoint:path} - Standard OpenAI passthrough route
* - /openai_passthrough/{endpoint:path} - Dedicated passthrough route (recommended for Responses API)
*
* Use /openai_passthrough/* when you need guaranteed passthrough to OpenAI without conflicts
* with LiteLLM's native implementations (e.g., for the Responses API at /v1/responses).
* Openai Passthrough Route
* @description Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
* implementations (e.g. the Responses API at /v1/responses).
*
* Examples:
* Standard route:
* - /openai/v1/chat/completions
* - /openai/v1/assistants
* - /openai/v1/threads
*
* Dedicated passthrough (for Responses API):
* - /openai_passthrough/v1/responses
* - /openai_passthrough/v1/responses/{response_id}
* - /openai_passthrough/v1/responses/{response_id}/input_items
*
* [Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
*/
delete: operations["openai_proxy_route_openai_passthrough__endpoint__delete"];
delete: operations["openai_passthrough_route_openai_passthrough__endpoint__delete"];
options?: never;
head?: never;
/**
* Openai Proxy Route
* @description Pass-through endpoint for OpenAI API calls.
*
* Available on both routes:
* - /openai/{endpoint:path} - Standard OpenAI passthrough route
* - /openai_passthrough/{endpoint:path} - Dedicated passthrough route (recommended for Responses API)
*
* Use /openai_passthrough/* when you need guaranteed passthrough to OpenAI without conflicts
* with LiteLLM's native implementations (e.g., for the Responses API at /v1/responses).
* Openai Passthrough Route
* @description Dedicated pass-through to the OpenAI API with no overlap with LiteLLM's native
* implementations (e.g. the Responses API at /v1/responses).
*
* Examples:
* Standard route:
* - /openai/v1/chat/completions
* - /openai/v1/assistants
* - /openai/v1/threads
*
* Dedicated passthrough (for Responses API):
* - /openai_passthrough/v1/responses
* - /openai_passthrough/v1/responses/{response_id}
* - /openai_passthrough/v1/responses/{response_id}/input_items
*
* [Docs](https://docs.litellm.ai/docs/pass_through/openai_passthrough)
*/
patch: operations["openai_proxy_route_openai_passthrough__endpoint__patch"];
patch: operations["openai_passthrough_route_openai_passthrough__endpoint__patch"];
trace?: never;
};
"/organization/daily/activity": {
@ -21891,52 +21791,6 @@ export interface paths {
patch?: never;
trace?: never;
};
"/vertex-ai/{endpoint}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Vertex Proxy Route
* @description Call LiteLLM proxy via Vertex AI SDK.
*
* [Docs](https://docs.litellm.ai/docs/pass_through/vertex_ai)
*/
get: operations["vertex_proxy_route_vertex_ai__endpoint__get_2"];
/**
* Vertex Proxy Route
* @description Call LiteLLM proxy via Vertex AI SDK.
*
* [Docs](https://docs.litellm.ai/docs/pass_through/vertex_ai)
*/
put: operations["vertex_proxy_route_vertex_ai__endpoint__put_2"];
/**
* Vertex Proxy Route
* @description Call LiteLLM proxy via Vertex AI SDK.
*
* [Docs](https://docs.litellm.ai/docs/pass_through/vertex_ai)
*/
post: operations["vertex_proxy_route_vertex_ai__endpoint__post_2"];
/**
* Vertex Proxy Route
* @description Call LiteLLM proxy via Vertex AI SDK.
*
* [Docs](https://docs.litellm.ai/docs/pass_through/vertex_ai)
*/
delete: operations["vertex_proxy_route_vertex_ai__endpoint__delete_2"];
options?: never;
head?: never;
/**
* Vertex Proxy Route
* @description Call LiteLLM proxy via Vertex AI SDK.
*
* [Docs](https://docs.litellm.ai/docs/pass_through/vertex_ai)
*/
patch: operations["vertex_proxy_route_vertex_ai__endpoint__patch_2"];
trace?: never;
};
"/vertex_ai/discovery/{endpoint}": {
parameters: {
query?: never;
@ -52513,24 +52367,6 @@ export interface operations {
};
};
};
websocket_openai_websocket_proxy_route_get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description WebSocket Protocol Switched */
101: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
chat_completion_openai_deployments__model__chat_completions_post: {
parameters: {
query?: never;
@ -53430,25 +53266,7 @@ export interface operations {
};
};
};
websocket_openai_websocket_proxy_route_get_2: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description WebSocket Protocol Switched */
101: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
openai_proxy_route_openai_passthrough__endpoint__get: {
openai_passthrough_route_openai_passthrough__endpoint__get: {
parameters: {
query?: never;
header?: never;
@ -53479,7 +53297,7 @@ export interface operations {
};
};
};
openai_proxy_route_openai_passthrough__endpoint__put: {
openai_passthrough_route_openai_passthrough__endpoint__put: {
parameters: {
query?: never;
header?: never;
@ -53510,7 +53328,7 @@ export interface operations {
};
};
};
openai_proxy_route_openai_passthrough__endpoint__post: {
openai_passthrough_route_openai_passthrough__endpoint__post: {
parameters: {
query?: never;
header?: never;
@ -53541,7 +53359,7 @@ export interface operations {
};
};
};
openai_proxy_route_openai_passthrough__endpoint__delete: {
openai_passthrough_route_openai_passthrough__endpoint__delete: {
parameters: {
query?: never;
header?: never;
@ -53572,7 +53390,7 @@ export interface operations {
};
};
};
openai_proxy_route_openai_passthrough__endpoint__patch: {
openai_passthrough_route_openai_passthrough__endpoint__patch: {
parameters: {
query?: never;
header?: never;
@ -67979,161 +67797,6 @@ export interface operations {
};
};
};
vertex_proxy_route_vertex_ai__endpoint__get_2: {
parameters: {
query?: never;
header?: never;
path: {
endpoint: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
vertex_proxy_route_vertex_ai__endpoint__put_2: {
parameters: {
query?: never;
header?: never;
path: {
endpoint: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
vertex_proxy_route_vertex_ai__endpoint__post_2: {
parameters: {
query?: never;
header?: never;
path: {
endpoint: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
vertex_proxy_route_vertex_ai__endpoint__delete_2: {
parameters: {
query?: never;
header?: never;
path: {
endpoint: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
vertex_proxy_route_vertex_ai__endpoint__patch_2: {
parameters: {
query?: never;
header?: never;
path: {
endpoint: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
vertex_discovery_proxy_route_vertex_ai_discovery__endpoint__get: {
parameters: {
query?: never;