mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-28 01:32:17 +00:00
fix: merge the duplicate charity_engine entry, and catch the next one
`provider_endpoints_support.json` declared `charity_engine` twice. `json.load()`
keeps the last of a repeated key and reports nothing, so the first copy was
silently discarded on every read.
The two copies were not identical. The discarded one carried two endpoint flags
the surviving one did not:
a2a: false
interactions: false
So the effect was not a harmless duplicate — an edit that added those two fields
never took effect, and nothing failed to say so. Removing the later copy restores
them (10 endpoint keys -> 12) and leaves every other provider byte-identical.
Added Test 0 to check_endpoint_coverage.py to stop this recurring. It re-reads the
raw file with `object_pairs_hook` rather than inspecting the parsed dict, because
by the time the dict exists the evidence is already gone — which is why the
existing checks, all of which read the parsed dict, could not see this.
Verified the check fails when it should: restoring the duplicate makes Test 0 name
`charity_engine` and raise; removing it again passes.
This commit is contained in:
parent
658f50663d
commit
215ced2bdb
2 changed files with 59 additions and 16 deletions
|
|
@ -2994,22 +2994,6 @@
|
|||
"rerank": false
|
||||
}
|
||||
},
|
||||
"charity_engine": {
|
||||
"display_name": "Charity Engine (`charity_engine`)",
|
||||
"url": "https://docs.litellm.ai/docs/providers/charity_engine",
|
||||
"endpoints": {
|
||||
"chat_completions": true,
|
||||
"messages": true,
|
||||
"responses": true,
|
||||
"embeddings": false,
|
||||
"image_generations": false,
|
||||
"audio_transcriptions": false,
|
||||
"audio_speech": false,
|
||||
"moderations": false,
|
||||
"batches": false,
|
||||
"rerank": false
|
||||
}
|
||||
},
|
||||
"empiriolabs": {
|
||||
"display_name": "EmpirioLabs (`empiriolabs`)",
|
||||
"url": "https://docs.litellm.ai/docs/providers/empiriolabs",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ This script:
|
|||
1. Extracts all endpoint entries from the "Supported Endpoints" section of sidebars.js
|
||||
2. Validates that each endpoint has a corresponding entry in the "endpoints" object of provider_endpoints_support.json
|
||||
3. Checks that the "docs_label" field is present in each endpoint definition
|
||||
4. Checks that no object in the file declares the same key twice
|
||||
"""
|
||||
|
||||
import json
|
||||
|
|
@ -20,6 +21,12 @@ class MissingEndpointDefinitionError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class DuplicateKeyError(Exception):
|
||||
"""Raised when provider_endpoints_support.json declares the same key twice in one object."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def get_repo_root() -> Path:
|
||||
"""Get the repository root directory."""
|
||||
# Check if litellm directory exists in current working directory
|
||||
|
|
@ -111,6 +118,36 @@ def load_provider_endpoints_file() -> Dict:
|
|||
return json.load(f)
|
||||
|
||||
|
||||
def find_duplicate_keys() -> List[Tuple[str, int]]:
|
||||
"""
|
||||
Find keys declared more than once inside the same JSON object.
|
||||
|
||||
json.load() keeps the last of a repeated key and reports no error, so an edit to
|
||||
the earlier copy is dropped without a trace: the file parses, CI passes, and the
|
||||
added fields simply are not there. That is why this check re-reads the raw file
|
||||
with object_pairs_hook instead of inspecting the parsed dict - the parsed dict
|
||||
has already lost the evidence.
|
||||
|
||||
Returns a list of (key, occurrences).
|
||||
"""
|
||||
repo_root = get_repo_root()
|
||||
file_path = repo_root / "provider_endpoints_support.json"
|
||||
|
||||
duplicates: List[Tuple[str, int]] = []
|
||||
|
||||
def collect(pairs):
|
||||
counts: Dict[str, int] = {}
|
||||
for key, _ in pairs:
|
||||
counts[key] = counts.get(key, 0) + 1
|
||||
duplicates.extend((key, n) for key, n in counts.items() if n > 1)
|
||||
return dict(pairs)
|
||||
|
||||
with open(file_path, "r") as f:
|
||||
json.loads(f.read(), object_pairs_hook=collect)
|
||||
|
||||
return duplicates
|
||||
|
||||
|
||||
def get_defined_endpoints(data: Dict) -> Dict[str, Dict]:
|
||||
"""Get all endpoint definitions from provider_endpoints_support.json."""
|
||||
return data.get("endpoints", {})
|
||||
|
|
@ -212,6 +249,28 @@ def main():
|
|||
|
||||
has_errors = False
|
||||
|
||||
# Test 0: Check for duplicate keys before anything reads the parsed file
|
||||
print("\n🔑 Test 0: Checking for duplicate keys...")
|
||||
duplicate_keys = find_duplicate_keys()
|
||||
|
||||
if duplicate_keys:
|
||||
error_msg = "\n❌ ERROR: The following keys are declared more than once in the same object:\n"
|
||||
error_msg += "=" * 70 + "\n"
|
||||
for key, occurrences in duplicate_keys:
|
||||
error_msg += f" - {key} ({occurrences} times)\n"
|
||||
error_msg += "\n" + "=" * 70 + "\n"
|
||||
error_msg += (
|
||||
"\n💡 Only the last copy survives parsing. Anything added to an earlier\n"
|
||||
)
|
||||
error_msg += " copy is silently discarded. Merge the copies into one entry.\n"
|
||||
print(error_msg)
|
||||
raise DuplicateKeyError(
|
||||
f"Duplicate key(s) in provider_endpoints_support.json: "
|
||||
f"{', '.join(key for key, _ in duplicate_keys)}"
|
||||
)
|
||||
|
||||
print("✅ No duplicate keys found!")
|
||||
|
||||
# Load provider_endpoints_support.json
|
||||
data = load_provider_endpoints_file()
|
||||
defined_endpoints = get_defined_endpoints(data)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue