Skip to content

Commit d01f28d

Browse files
authored
Feature:Enhance backend model validate response (#397)
2 parents 8f8788f + deb65a2 commit d01f28d

File tree

3 files changed

+244
-102
lines changed

3 files changed

+244
-102
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import json
2+
import re
3+
4+
5+
def normalize_error_to_openai_format(exception: Exception) -> tuple[str, str | None, dict | None]:
6+
"""
7+
Normalize error to OpenAI-style error structure.
8+
9+
Args:
10+
exception: The exception to normalize
11+
12+
Returns:
13+
tuple: (message, error_code, error_object)
14+
"""
15+
raw_msg = str(exception)
16+
error_obj = None
17+
error_code = None
18+
message = raw_msg
19+
20+
# Match "Error code: <code> - {json}"
21+
m = re.search(r"Error code:\s*(\d+)\s*-\s*(\{.*\})", raw_msg, re.DOTALL)
22+
if m:
23+
error_code = m.group(1)
24+
try:
25+
parsed = json.loads(m.group(2))
26+
err = parsed.get("error") or parsed
27+
if isinstance(err, dict):
28+
error_obj = {
29+
"message": err.get("message"),
30+
"type": err.get("type"),
31+
"param": err.get("param"),
32+
"code": err.get("code"),
33+
}
34+
if err.get("message"):
35+
message = err.get("message")
36+
if err.get("code"):
37+
error_code = err.get("code")
38+
except Exception:
39+
pass
40+
41+
# Heuristics if not parsed
42+
if error_obj is None:
43+
lower = raw_msg.lower()
44+
if "invalid_api_key" in lower or "incorrect api key" in lower or "unauthorized" in lower or " 401" in lower:
45+
error_code = "invalid_api_key"
46+
message = "Invalid key. Validation failed."
47+
error_obj = {
48+
"message": message,
49+
"type": "invalid_request_error",
50+
"param": None,
51+
"code": "invalid_api_key",
52+
}
53+
elif "model_not_found" in lower or "does not exist" in lower or " 404" in lower:
54+
error_code = "model_not_found"
55+
message = "Invalid model name. Validation failed."
56+
error_obj = {
57+
"message": message,
58+
"type": "invalid_request_error",
59+
"param": None,
60+
"code": "model_not_found",
61+
}
62+
elif "insufficient_quota" in lower or "quota" in lower or " 429" in lower:
63+
error_code = "insufficient_quota"
64+
message = "You exceeded your current quota, please check your plan and billing details."
65+
error_obj = {
66+
"message": message,
67+
"type": "insufficient_quota",
68+
"param": None,
69+
"code": "insufficient_quota",
70+
}
71+
72+
return message, error_code, error_obj

backend/app/controller/model_controller.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from fastapi import APIRouter
22
from pydantic import BaseModel, Field
33
from app.component.model_validation import create_agent
4+
from camel.types import ModelType
5+
from app.component.error_format import normalize_error_to_openai_format
46

57

68
router = APIRouter(tags=["model"])
@@ -18,12 +20,48 @@ class ValidateModelRequest(BaseModel):
1820
class ValidateModelResponse(BaseModel):
1921
is_valid: bool = Field(..., description="Is valid")
2022
is_tool_calls: bool = Field(..., description="Is tool call used")
23+
error_code: str | None = Field(None, description="Error code")
24+
error: dict | None = Field(None, description="OpenAI-style error object")
2125
message: str = Field(..., description="Message")
2226

2327

2428
@router.post("/model/validate")
2529
async def validate_model(request: ValidateModelRequest):
2630
try:
31+
# 1) API key validation
32+
if request.api_key is not None and str(request.api_key).strip() == "":
33+
return ValidateModelResponse(
34+
is_valid=False,
35+
is_tool_calls=False,
36+
message="Invalid key. Validation failed.",
37+
error_code="invalid_api_key",
38+
error={
39+
"message": "Invalid key. Validation failed.",
40+
"type": "invalid_request_error",
41+
"param": None,
42+
"code": "invalid_api_key",
43+
},
44+
)
45+
46+
# 2) Model name validation
47+
if request.model_type:
48+
try:
49+
# Will raise if not a valid enum name
50+
_ = ModelType.from_name(request.model_type)
51+
except Exception as e:
52+
return ValidateModelResponse(
53+
is_valid=False,
54+
is_tool_calls=False,
55+
message="Invalid model name. Validation failed.",
56+
error_code=f"model_not_found : {e}",
57+
error={
58+
"message": "Invalid model name. Validation failed.",
59+
"type": "invalid_request_error",
60+
"param": None,
61+
"code": "model_not_found",
62+
},
63+
)
64+
2765
extra = request.extra_params or {}
2866

2967
agent = create_agent(
@@ -43,17 +81,33 @@ async def validate_model(request: ValidateModelRequest):
4381
"""
4482
)
4583
except Exception as e:
46-
return ValidateModelResponse(is_valid=False, is_tool_calls=False, message=str(e))
84+
# Normalize error to OpenAI-style error structure
85+
message, error_code, error_obj = normalize_error_to_openai_format(e)
86+
87+
return ValidateModelResponse(
88+
is_valid=False,
89+
is_tool_calls=False,
90+
message=message,
91+
error_code=error_code,
92+
error=error_obj,
93+
)
4794
is_valid = bool(response)
4895
is_tool_calls = False
49-
50-
if response and hasattr(response, 'info') and response.info:
96+
97+
if response and hasattr(response, "info") and response.info:
5198
tool_calls = response.info.get("tool_calls", [])
5299
if tool_calls and len(tool_calls) > 0:
53-
is_tool_calls = tool_calls[0].result == "Tool execution completed successfully for https://www.camel-ai.org, Website Content: Welcome to CAMEL AI!"
54-
100+
is_tool_calls = (
101+
tool_calls[0].result
102+
== "Tool execution completed successfully for https://www.camel-ai.org, Website Content: Welcome to CAMEL AI!"
103+
)
104+
55105
return ValidateModelResponse(
56106
is_valid=is_valid,
57107
is_tool_calls=is_tool_calls,
58-
message="",
108+
message="Validation Success"
109+
if is_tool_calls
110+
else "This model doesn't support tool calls. please try with another model.",
111+
error_code=None,
112+
error=None,
59113
)

0 commit comments

Comments
 (0)