Skip to content

Commit 12e41d6

Browse files
committed
Simplify custom endpoint management system
- Remove unnecessary endpoint_id field (use model_id + provider_type as natural unique key) - Remove display_name, created_at, updated_at metadata fields (not needed for server operations) - Remove endpoint_url from Bedrock/OpenAI/Gemini (they use standard APIs) - Keep endpoint_url only for CAII and OpenAI Compatible (custom deployments) - Update API endpoints to use /model_id/provider_type pattern - Simplify JSON storage structure to use model_id:provider_type keys - Test confirmed: server starts and endpoints work correctly
1 parent 3fa8d23 commit 12e41d6

File tree

6 files changed

+79
-117
lines changed

6 files changed

+79
-117
lines changed

app/core/custom_endpoint_manager.py

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
class CustomEndpointManager:
16-
"""Manager for custom model endpoints"""
16+
"""Manager for custom model endpoints - simplified"""
1717

1818
def __init__(self, config_file: str = "custom_model_endpoints.json"):
1919
"""
@@ -30,9 +30,7 @@ def _ensure_config_file_exists(self):
3030
if not self.config_file.exists():
3131
initial_config = {
3232
"version": "1.0",
33-
"endpoints": {},
34-
"created_at": datetime.now(timezone.utc).isoformat(),
35-
"last_updated": datetime.now(timezone.utc).isoformat()
33+
"endpoints": {}
3634
}
3735
with open(self.config_file, 'w') as f:
3836
json.dump(initial_config, f, indent=2)
@@ -48,7 +46,6 @@ def _load_config(self) -> Dict[str, Any]:
4846
def _save_config(self, config: Dict[str, Any]):
4947
"""Save configuration to file"""
5048
try:
51-
config["last_updated"] = datetime.now(timezone.utc).isoformat()
5249
with open(self.config_file, 'w') as f:
5350
json.dump(config, f, indent=2)
5451
except Exception as e:
@@ -62,40 +59,40 @@ def add_endpoint(self, endpoint: CustomEndpoint) -> str:
6259
endpoint: Custom endpoint configuration
6360
6461
Returns:
65-
endpoint_id: The ID of the added endpoint
62+
unique_key: The unique key for the added endpoint (model_id:provider_type)
6663
6764
Raises:
6865
APIError: If endpoint already exists or validation fails
6966
"""
7067
config = self._load_config()
7168

72-
# Check if endpoint_id already exists
73-
if endpoint.endpoint_id in config["endpoints"]:
74-
raise APIError(f"Endpoint with ID '{endpoint.endpoint_id}' already exists", 400)
69+
# Use model_id + provider_type as unique key
70+
unique_key = f"{endpoint.model_id}:{endpoint.provider_type}"
7571

76-
# Add timestamps
77-
now = datetime.now(timezone.utc).isoformat()
78-
endpoint.created_at = now
79-
endpoint.updated_at = now
72+
# Check if endpoint already exists
73+
if unique_key in config["endpoints"]:
74+
raise APIError(f"Endpoint for model '{endpoint.model_id}' with provider '{endpoint.provider_type}' already exists", 400)
8075

8176
# Store endpoint configuration
82-
config["endpoints"][endpoint.endpoint_id] = endpoint.model_dump()
77+
config["endpoints"][unique_key] = endpoint.model_dump()
8378

8479
self._save_config(config)
85-
return endpoint.endpoint_id
80+
return unique_key
8681

87-
def get_endpoint(self, endpoint_id: str) -> Optional[CustomEndpoint]:
82+
def get_endpoint(self, model_id: str, provider_type: str) -> Optional[CustomEndpoint]:
8883
"""
89-
Get a specific custom endpoint by ID
84+
Get a specific custom endpoint by model_id and provider_type
9085
9186
Args:
92-
endpoint_id: The endpoint ID to retrieve
87+
model_id: The model identifier
88+
provider_type: The provider type
9389
9490
Returns:
9591
CustomEndpoint or None if not found
9692
"""
9793
config = self._load_config()
98-
endpoint_data = config["endpoints"].get(endpoint_id)
94+
unique_key = f"{model_id}:{provider_type}"
95+
endpoint_data = config["endpoints"].get(unique_key)
9996

10097
if not endpoint_data:
10198
return None
@@ -112,12 +109,12 @@ def get_all_endpoints(self) -> List[CustomEndpoint]:
112109
config = self._load_config()
113110
endpoints = []
114111

115-
for endpoint_data in config["endpoints"].values():
112+
for unique_key, endpoint_data in config["endpoints"].items():
116113
try:
117114
endpoint = self._parse_endpoint(endpoint_data)
118115
endpoints.append(endpoint)
119116
except Exception as e:
120-
print(f"Warning: Failed to parse endpoint {endpoint_data.get('endpoint_id', 'unknown')}: {e}")
117+
print(f"Warning: Failed to parse endpoint {unique_key}: {e}")
121118
continue
122119

123120
return endpoints
@@ -135,12 +132,13 @@ def get_endpoints_by_provider(self, provider_type: str) -> List[CustomEndpoint]:
135132
all_endpoints = self.get_all_endpoints()
136133
return [ep for ep in all_endpoints if ep.provider_type == provider_type]
137134

138-
def update_endpoint(self, endpoint_id: str, updated_endpoint: CustomEndpoint) -> bool:
135+
def update_endpoint(self, model_id: str, provider_type: str, updated_endpoint: CustomEndpoint) -> bool:
139136
"""
140137
Update an existing custom endpoint
141138
142139
Args:
143-
endpoint_id: The endpoint ID to update
140+
model_id: The model identifier
141+
provider_type: The provider type
144142
updated_endpoint: Updated endpoint configuration
145143
146144
Returns:
@@ -151,39 +149,36 @@ def update_endpoint(self, endpoint_id: str, updated_endpoint: CustomEndpoint) ->
151149
"""
152150
config = self._load_config()
153151

154-
if endpoint_id not in config["endpoints"]:
155-
return False
156-
157-
# Preserve original created_at timestamp
158-
original_created_at = config["endpoints"][endpoint_id].get("created_at")
152+
unique_key = f"{model_id}:{provider_type}"
159153

160-
# Update timestamps
161-
updated_endpoint.created_at = original_created_at
162-
updated_endpoint.updated_at = datetime.now(timezone.utc).isoformat()
163-
updated_endpoint.endpoint_id = endpoint_id # Ensure ID consistency
154+
if unique_key not in config["endpoints"]:
155+
return False
164156

165157
# Update endpoint configuration
166-
config["endpoints"][endpoint_id] = updated_endpoint.model_dump()
158+
config["endpoints"][unique_key] = updated_endpoint.model_dump()
167159

168160
self._save_config(config)
169161
return True
170162

171-
def delete_endpoint(self, endpoint_id: str) -> bool:
163+
def delete_endpoint(self, model_id: str, provider_type: str) -> bool:
172164
"""
173165
Delete a custom endpoint
174166
175167
Args:
176-
endpoint_id: The endpoint ID to delete
168+
model_id: The model identifier
169+
provider_type: The provider type
177170
178171
Returns:
179172
True if deleted successfully, False if endpoint not found
180173
"""
181174
config = self._load_config()
182175

183-
if endpoint_id not in config["endpoints"]:
176+
unique_key = f"{model_id}:{provider_type}"
177+
178+
if unique_key not in config["endpoints"]:
184179
return False
185180

186-
del config["endpoints"][endpoint_id]
181+
del config["endpoints"][unique_key]
187182
self._save_config(config)
188183
return True
189184

@@ -218,23 +213,6 @@ def _parse_endpoint(self, endpoint_data: Dict[str, Any]) -> CustomEndpoint:
218213
except Exception as e:
219214
raise APIError(f"Failed to parse endpoint configuration: {str(e)}", 500)
220215

221-
def validate_endpoint_id(self, endpoint_id: str) -> bool:
222-
"""
223-
Validate endpoint ID format
224-
225-
Args:
226-
endpoint_id: The endpoint ID to validate
227-
228-
Returns:
229-
True if valid, False otherwise
230-
"""
231-
if not endpoint_id or not isinstance(endpoint_id, str):
232-
return False
233-
234-
# Allow alphanumeric, hyphens, and underscores
235-
import re
236-
return bool(re.match(r'^[a-zA-Z0-9_-]+$', endpoint_id))
237-
238216
def get_endpoint_stats(self) -> Dict[str, Any]:
239217
"""
240218
Get statistics about custom endpoints
@@ -245,12 +223,14 @@ def get_endpoint_stats(self) -> Dict[str, Any]:
245223
endpoints = self.get_all_endpoints()
246224

247225
provider_counts = {}
226+
model_list = []
248227
for endpoint in endpoints:
249228
provider_type = endpoint.provider_type
250229
provider_counts[provider_type] = provider_counts.get(provider_type, 0) + 1
230+
model_list.append(f"{endpoint.model_id} ({endpoint.provider_type})")
251231

252232
return {
253233
"total_endpoints": len(endpoints),
254234
"provider_counts": provider_counts,
255-
"endpoint_ids": [ep.endpoint_id for ep in endpoints]
235+
"models": model_list
256236
}

app/core/model_endpoints.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,17 +388,13 @@ async def collect_model_catalog() -> Dict[str, Dict[str, List[str]]]:
388388
catalog[provider_key]["enabled"].append({
389389
"model": endpoint.model_id,
390390
"endpoint": getattr(endpoint, 'endpoint_url', ''),
391-
"custom": True,
392-
"endpoint_id": endpoint.endpoint_id,
393-
"display_name": endpoint.display_name
391+
"custom": True
394392
})
395393
else:
396394
# Other providers: just the model name with custom metadata
397395
catalog[provider_key]["enabled"].append({
398396
"model": endpoint.model_id,
399397
"custom": True,
400-
"endpoint_id": endpoint.endpoint_id,
401-
"display_name": endpoint.display_name,
402398
"provider_type": endpoint.provider_type
403399
})
404400

app/core/model_handlers.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,8 @@ def get_custom_endpoint_config(model_id: str, provider_type: str):
3333
from app.core.custom_endpoint_manager import CustomEndpointManager
3434

3535
custom_manager = CustomEndpointManager()
36-
custom_endpoints = custom_manager.get_endpoints_by_provider(provider_type)
37-
38-
# Find endpoint matching the model_id
39-
for endpoint in custom_endpoints:
40-
if endpoint.model_id == model_id:
41-
return endpoint
36+
return custom_manager.get_endpoint(model_id, provider_type)
4237

43-
return None
4438
except Exception as e:
4539
print(f"Warning: Failed to get custom endpoint config: {e}")
4640
return None

app/main.py

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,19 +1488,14 @@ async def perform_upgrade():
14881488
async def add_custom_model_endpoint(request: AddCustomEndpointRequest):
14891489
"""Add a new custom model endpoint"""
14901490
try:
1491-
# Validate endpoint ID format
1492-
if not custom_endpoint_manager.validate_endpoint_id(request.endpoint_config.endpoint_id):
1493-
raise HTTPException(
1494-
status_code=400,
1495-
detail="Invalid endpoint ID. Use only alphanumeric characters, hyphens, and underscores."
1496-
)
1497-
1498-
endpoint_id = custom_endpoint_manager.add_endpoint(request.endpoint_config)
1491+
unique_key = custom_endpoint_manager.add_endpoint(request.endpoint_config)
14991492

15001493
return {
15011494
"status": "success",
1502-
"message": f"Custom endpoint '{endpoint_id}' added successfully",
1503-
"endpoint_id": endpoint_id
1495+
"message": f"Custom endpoint for '{request.endpoint_config.model_id}' ({request.endpoint_config.provider_type}) added successfully",
1496+
"model_id": request.endpoint_config.model_id,
1497+
"provider_type": request.endpoint_config.provider_type,
1498+
"unique_key": unique_key
15041499
}
15051500

15061501
except APIError as e:
@@ -1530,17 +1525,17 @@ async def list_custom_model_endpoints(provider_type: Optional[str] = None):
15301525
raise HTTPException(status_code=500, detail=f"Failed to list custom endpoints: {str(e)}")
15311526

15321527

1533-
@app.get("/custom_model_endpoints/{endpoint_id}", include_in_schema=True, responses=responses,
1528+
@app.get("/custom_model_endpoints/{model_id}/{provider_type}", include_in_schema=True, responses=responses,
15341529
description="Get a specific custom model endpoint")
1535-
async def get_custom_model_endpoint(endpoint_id: str):
1530+
async def get_custom_model_endpoint(model_id: str, provider_type: str):
15361531
"""Get details of a specific custom model endpoint"""
15371532
try:
1538-
endpoint = custom_endpoint_manager.get_endpoint(endpoint_id)
1533+
endpoint = custom_endpoint_manager.get_endpoint(model_id, provider_type)
15391534

15401535
if not endpoint:
15411536
raise HTTPException(
15421537
status_code=404,
1543-
detail=f"Custom endpoint '{endpoint_id}' not found"
1538+
detail=f"Custom endpoint for model '{model_id}' with provider '{provider_type}' not found"
15441539
)
15451540

15461541
return {
@@ -1554,29 +1549,29 @@ async def get_custom_model_endpoint(endpoint_id: str):
15541549
raise HTTPException(status_code=500, detail=f"Failed to get custom endpoint: {str(e)}")
15551550

15561551

1557-
@app.put("/custom_model_endpoints/{endpoint_id}", include_in_schema=True, responses=responses,
1552+
@app.put("/custom_model_endpoints/{model_id}/{provider_type}", include_in_schema=True, responses=responses,
15581553
description="Update a custom model endpoint")
1559-
async def update_custom_model_endpoint(endpoint_id: str, request: AddCustomEndpointRequest):
1554+
async def update_custom_model_endpoint(model_id: str, provider_type: str, request: AddCustomEndpointRequest):
15601555
"""Update an existing custom model endpoint"""
15611556
try:
1562-
# Ensure the endpoint ID in the request matches the URL parameter
1563-
if request.endpoint_config.endpoint_id != endpoint_id:
1557+
# Ensure the model_id and provider_type in the request match the URL parameters
1558+
if request.endpoint_config.model_id != model_id or request.endpoint_config.provider_type != provider_type:
15641559
raise HTTPException(
15651560
status_code=400,
1566-
detail="Endpoint ID in request body must match the URL parameter"
1561+
detail="Model ID and provider type in request body must match the URL parameters"
15671562
)
15681563

1569-
success = custom_endpoint_manager.update_endpoint(endpoint_id, request.endpoint_config)
1564+
success = custom_endpoint_manager.update_endpoint(model_id, provider_type, request.endpoint_config)
15701565

15711566
if not success:
15721567
raise HTTPException(
15731568
status_code=404,
1574-
detail=f"Custom endpoint '{endpoint_id}' not found"
1569+
detail=f"Custom endpoint for model '{model_id}' with provider '{provider_type}' not found"
15751570
)
15761571

15771572
return {
15781573
"status": "success",
1579-
"message": f"Custom endpoint '{endpoint_id}' updated successfully"
1574+
"message": f"Custom endpoint for '{model_id}' ({provider_type}) updated successfully"
15801575
}
15811576

15821577
except APIError as e:
@@ -1585,22 +1580,22 @@ async def update_custom_model_endpoint(endpoint_id: str, request: AddCustomEndpo
15851580
raise HTTPException(status_code=500, detail=f"Failed to update custom endpoint: {str(e)}")
15861581

15871582

1588-
@app.delete("/custom_model_endpoints/{endpoint_id}", include_in_schema=True, responses=responses,
1583+
@app.delete("/custom_model_endpoints/{model_id}/{provider_type}", include_in_schema=True, responses=responses,
15891584
description="Delete a custom model endpoint")
1590-
async def delete_custom_model_endpoint(endpoint_id: str):
1585+
async def delete_custom_model_endpoint(model_id: str, provider_type: str):
15911586
"""Delete a custom model endpoint"""
15921587
try:
1593-
success = custom_endpoint_manager.delete_endpoint(endpoint_id)
1588+
success = custom_endpoint_manager.delete_endpoint(model_id, provider_type)
15941589

15951590
if not success:
15961591
raise HTTPException(
15971592
status_code=404,
1598-
detail=f"Custom endpoint '{endpoint_id}' not found"
1593+
detail=f"Custom endpoint for model '{model_id}' with provider '{provider_type}' not found"
15991594
)
16001595

16011596
return {
16021597
"status": "success",
1603-
"message": f"Custom endpoint '{endpoint_id}' deleted successfully"
1598+
"message": f"Custom endpoint for '{model_id}' ({provider_type}) deleted successfully"
16041599
}
16051600

16061601
except APIError as e:

0 commit comments

Comments
 (0)