@@ -1019,6 +1019,11 @@ def get_openapi_schema():
10191019
10201020 openapi_schema = CustomOpenAPISpec.add_llm_api_request_schema_body(openapi_schema)
10211021
1022+ # Stub unloaded lazy features so they appear as Swagger sections.
1023+ from litellm.proxy._lazy_features import inject_lazy_stubs
1024+
1025+ openapi_schema = inject_lazy_stubs(openapi_schema)
1026+
10221027 # Fix Swagger UI execute path error when server_root_path is set
10231028 if server_root_path:
10241029 openapi_schema["servers"] = [{"url": "/" + server_root_path.strip("/")}]
@@ -1045,6 +1050,11 @@ def custom_openapi():
10451050
10461051 openapi_schema = CustomOpenAPISpec.add_llm_api_request_schema_body(openapi_schema)
10471052
1053+ # Stub unloaded lazy features so they appear as Swagger sections.
1054+ from litellm.proxy._lazy_features import inject_lazy_stubs
1055+
1056+ openapi_schema = inject_lazy_stubs(openapi_schema)
1057+
10481058 # Fix Swagger UI execute path error when server_root_path is set
10491059 if server_root_path:
10501060 openapi_schema["servers"] = [{"url": "/" + server_root_path.strip("/")}]
@@ -1472,14 +1482,40 @@ def mount_swagger_ui():
14721482
14731483 app.mount("/swagger", StaticFiles(directory=swagger_directory), name="swagger")
14741484
1485+ # On dropdown expand: one-time fetch to the prefix (triggers lazy load),
1486+ # then spec re-download so real routes replace the stub. Raw JS (no
1487+ # <script> tag) since it's injected inside the existing inline script.
1488+ from fastapi.responses import HTMLResponse
1489+
1490+ from litellm.proxy._lazy_features import lazy_tag_to_prefix
1491+
1492+ _lazy_plugin_js = (
1493+ "const TAG_TO_PREFIX = "
1494+ + json.dumps(lazy_tag_to_prefix())
1495+ + ";const warmedTags = new Set();const LazyLoadPlugin = () => ({"
1496+ "statePlugins:{layout:{wrapActions:{show:(ori,sys)=>(...args)=>{"
1497+ "const thing=args[0];let tag=null;"
1498+ "if(Array.isArray(thing)){for(const t of thing)if(TAG_TO_PREFIX[t])tag=t;}"
1499+ "if(tag&&!warmedTags.has(tag)){warmedTags.add(tag);"
1500+ "fetch(TAG_TO_PREFIX[tag]).finally(()=>setTimeout(()=>sys.specActions.download(),800));}"
1501+ "return ori(...args);}}}}});"
1502+ )
1503+
14751504 def swagger_monkey_patch(*args, **kwargs):
1476- return get_swagger_ui_html(
1505+ response = get_swagger_ui_html(
14771506 *args,
14781507 **kwargs,
14791508 swagger_js_url=f"{custom_root_path_swagger_path}/swagger-ui-bundle.js",
14801509 swagger_css_url=f"{custom_root_path_swagger_path}/swagger-ui.css",
14811510 swagger_favicon_url=f"{custom_root_path_swagger_path}/favicon.png",
14821511 )
1512+ body = response.body.decode("utf-8")
1513+ body = body.replace(
1514+ "const ui = SwaggerUIBundle({",
1515+ _lazy_plugin_js + "const ui = SwaggerUIBundle({plugins:[LazyLoadPlugin],",
1516+ 1,
1517+ )
1518+ return HTMLResponse(content=body)
14831519
14841520 applications.get_swagger_ui_html = swagger_monkey_patch
14851521
0 commit comments