mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/remaining-table-complexity-053477
This commit is contained in:
commit
fe57eedb5c
4 changed files with 175 additions and 0 deletions
|
|
@ -92,6 +92,89 @@
|
|||
{ "name": "trash_message", "description": "Move a message to trash" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "google_sheets",
|
||||
"title": "Google Sheets",
|
||||
"description": "Read, write, and format data in Google Sheets spreadsheets",
|
||||
"icon_url": "https://cdn.simpleicons.org/googlesheets",
|
||||
"spec_url": "https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/googleapis.com/sheets/v4/openapi.yaml",
|
||||
"oauth": {
|
||||
"authorization_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"pkce": true,
|
||||
"docs_url": "https://developers.google.com/sheets/api/guides/authorizing"
|
||||
},
|
||||
"key_tools": [
|
||||
{ "name": "create_spreadsheet", "description": "Create a new spreadsheet" },
|
||||
{ "name": "get_spreadsheet", "description": "Get spreadsheet metadata and sheet properties" },
|
||||
{ "name": "get_values", "description": "Read cell values from a range" },
|
||||
{ "name": "update_values", "description": "Write cell values to a range" },
|
||||
{ "name": "append_values", "description": "Append rows of values to a range" },
|
||||
{ "name": "clear_values", "description": "Clear cell values in a range" },
|
||||
{ "name": "batch_update", "description": "Apply batched formatting and structural updates" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "google_drive",
|
||||
"title": "Google Drive",
|
||||
"description": "List, read, upload, and manage files in Google Drive",
|
||||
"icon_url": "https://cdn.simpleicons.org/googledrive",
|
||||
"spec_url": "https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/googleapis.com/drive/v3/openapi.yaml",
|
||||
"oauth": {
|
||||
"authorization_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"pkce": true,
|
||||
"docs_url": "https://developers.google.com/drive/api/guides/api-specific-auth"
|
||||
},
|
||||
"key_tools": [
|
||||
{ "name": "list_files", "description": "List and search files" },
|
||||
{ "name": "get_file", "description": "Get file metadata" },
|
||||
{ "name": "create_file", "description": "Create a file or folder" },
|
||||
{ "name": "update_file", "description": "Update file metadata or content" },
|
||||
{ "name": "copy_file", "description": "Copy a file" },
|
||||
{ "name": "delete_file", "description": "Delete a file" },
|
||||
{ "name": "list_permissions", "description": "List sharing permissions on a file" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "google_calendar",
|
||||
"title": "Google Calendar",
|
||||
"description": "Read and manage Google Calendar events and calendars",
|
||||
"icon_url": "https://cdn.simpleicons.org/googlecalendar",
|
||||
"spec_url": "https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/googleapis.com/calendar/v3/openapi.yaml",
|
||||
"oauth": {
|
||||
"authorization_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"pkce": true,
|
||||
"docs_url": "https://developers.google.com/workspace/calendar/api/guides/auth"
|
||||
},
|
||||
"key_tools": [
|
||||
{ "name": "list_events", "description": "List events on a calendar" },
|
||||
{ "name": "get_event", "description": "Get a single event" },
|
||||
{ "name": "insert_event", "description": "Create an event" },
|
||||
{ "name": "update_event", "description": "Update an event" },
|
||||
{ "name": "delete_event", "description": "Delete an event" },
|
||||
{ "name": "query_freebusy", "description": "Query free/busy availability" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "google_docs",
|
||||
"title": "Google Docs",
|
||||
"description": "Create, read, and edit Google Docs documents",
|
||||
"icon_url": "https://cdn.simpleicons.org/googledocs",
|
||||
"spec_url": "https://raw.githubusercontent.com/APIs-guru/openapi-directory/main/APIs/googleapis.com/docs/v1/openapi.yaml",
|
||||
"oauth": {
|
||||
"authorization_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"pkce": true,
|
||||
"docs_url": "https://developers.google.com/docs/api/how-tos/authorizing"
|
||||
},
|
||||
"key_tools": [
|
||||
{ "name": "create_document", "description": "Create a new document" },
|
||||
{ "name": "get_document", "description": "Get a document's full content" },
|
||||
{ "name": "batch_update_document", "description": "Apply batched edits to a document" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stripe",
|
||||
"title": "Stripe",
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False):
|
|||
"realtime",
|
||||
]
|
||||
]
|
||||
supported_endpoints: Optional[List[str]]
|
||||
use_openai_responses_path: Optional[bool]
|
||||
tpm: Optional[int]
|
||||
rpm: Optional[int]
|
||||
provider_specific_entry: Optional[Dict[str, float]]
|
||||
|
|
|
|||
|
|
@ -5376,3 +5376,41 @@ async def test_edit_mcp_server_snapshot_failure_skips_purge_but_edit_succeeds():
|
|||
|
||||
assert result.server_id == server_id
|
||||
mock_purge.assert_not_awaited()
|
||||
|
||||
|
||||
def test_bundled_openapi_registry_parses_and_entries_are_well_formed():
|
||||
"""The OpenAPI quick-picker registry ships as a bundled JSON file; a malformed file or entry
|
||||
silently degrades the picker to empty (the endpoint swallows load errors), so pin the file's
|
||||
shape here: it must parse, and every entry needs the fields the create-form prefill reads.
|
||||
OAuth-capable entries must carry both endpoint URLs; a catalog entry with a blank
|
||||
authorization_url would recreate the exact 400 ("authorization url is not set") the catalog
|
||||
exists to prevent for spec-only servers, which never run OAuth endpoint discovery."""
|
||||
import json
|
||||
import os
|
||||
|
||||
registry_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"..", "..", "..", "..", "litellm", "proxy", "openapi_registry.json",
|
||||
)
|
||||
with open(registry_path) as f:
|
||||
registry = json.load(f)
|
||||
|
||||
apis = registry["apis"]
|
||||
assert apis, "registry must not be empty"
|
||||
names = [entry["name"] for entry in apis]
|
||||
assert len(names) == len(set(names)), "duplicate registry entry names"
|
||||
for google_entry in ("google_sheets", "google_drive", "google_calendar", "google_docs"):
|
||||
assert google_entry in names, f"LIT-4629: {google_entry} must be in the catalog"
|
||||
|
||||
for entry in apis:
|
||||
for required in ("name", "title", "description", "icon_url", "spec_url"):
|
||||
assert entry.get(required), f"{entry.get('name')}: missing {required}"
|
||||
assert entry["spec_url"].startswith("https://"), f"{entry['name']}: non-https spec_url"
|
||||
oauth = entry.get("oauth")
|
||||
if oauth is not None:
|
||||
for required in ("authorization_url", "token_url"):
|
||||
assert oauth.get(required, "").startswith("https://"), (
|
||||
f"{entry['name']}: oauth.{required} must be a non-empty https URL"
|
||||
)
|
||||
for tool in entry.get("key_tools", []):
|
||||
assert tool.get("name") and tool.get("description"), f"{entry['name']}: malformed key_tool"
|
||||
|
|
|
|||
|
|
@ -803,6 +803,8 @@ def test_shared_backend_model_info_keeps_schema_fields_and_drops_the_rest():
|
|||
"litellm_provider": "openai",
|
||||
"max_tokens": 128000,
|
||||
"supports_vision": True,
|
||||
"supported_endpoints": ["/v1/responses"],
|
||||
"use_openai_responses_path": True,
|
||||
"input_cost_per_token": 0.99,
|
||||
"output_cost_per_token": 0.99,
|
||||
"id": "deploy-a",
|
||||
|
|
@ -818,9 +820,59 @@ def test_shared_backend_model_info_keeps_schema_fields_and_drops_the_rest():
|
|||
"litellm_provider": "openai",
|
||||
"max_tokens": 128000,
|
||||
"supports_vision": True,
|
||||
"supported_endpoints": ["/v1/responses"],
|
||||
"use_openai_responses_path": True,
|
||||
}
|
||||
|
||||
|
||||
def test_capability_flags_propagate_from_deployment_model_info_to_shared_key():
|
||||
"""Backend-model capability facts (supported_endpoints,
|
||||
use_openai_responses_path) declared in a deployment's model_info must reach
|
||||
the shared backend key: the Bedrock Mantle routing gates read them raw off
|
||||
litellm.model_cost and document proxy model_info as an override path for
|
||||
models missing from the built-in cost map.
|
||||
"""
|
||||
from litellm.llms.bedrock_mantle.common_utils import (
|
||||
mantle_base_segment,
|
||||
mantle_supports_responses,
|
||||
)
|
||||
|
||||
bare_model = "somelab.lit4544-unmapped-model"
|
||||
backend_model = f"bedrock_mantle/{bare_model}"
|
||||
deploy_id = "lit4544-mantle-deploy"
|
||||
|
||||
model_keys = {
|
||||
key: copy.deepcopy(litellm.model_cost.get(key))
|
||||
for key in (bare_model, backend_model, deploy_id)
|
||||
}
|
||||
try:
|
||||
Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "mantle-alias",
|
||||
"litellm_params": {
|
||||
"model": backend_model,
|
||||
"api_key": "fake-key",
|
||||
},
|
||||
"model_info": {
|
||||
"id": deploy_id,
|
||||
"supported_endpoints": ["/v1/responses"],
|
||||
"use_openai_responses_path": True,
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
shared_entry = litellm.model_cost.get(backend_model) or {}
|
||||
assert shared_entry.get("supported_endpoints") == ["/v1/responses"]
|
||||
assert shared_entry.get("use_openai_responses_path") is True
|
||||
assert "id" not in shared_entry
|
||||
assert mantle_supports_responses(bare_model, litellm.model_cost) is True
|
||||
assert mantle_base_segment(bare_model, litellm.model_cost) == "openai/v1"
|
||||
finally:
|
||||
_restore_model_cost_entries(model_keys)
|
||||
|
||||
|
||||
def test_wildcard_zero_cost_request_does_not_poison_named_deployment_pricing():
|
||||
"""LIT-3991 end to end: a proxy has a named text-embedding-3-small
|
||||
deployment relying on built-in pricing plus an ``openai/*`` wildcard with
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue