fix: mcp anyOf support (#7941)
* improve anyOf support * explicitly handle simple nullable types * mypy
This commit is contained in:
parent
2bfb2c02c3
commit
d84ae71e7d
1 changed files with 27 additions and 8 deletions
|
|
@ -17,6 +17,7 @@ from sqlmodel import select
|
||||||
from langflow.services.database.models import Flow
|
from langflow.services.database.models import Flow
|
||||||
|
|
||||||
HTTP_ERROR_STATUS_CODE = httpx_codes.BAD_REQUEST # HTTP status code for client errors
|
HTTP_ERROR_STATUS_CODE = httpx_codes.BAD_REQUEST # HTTP status code for client errors
|
||||||
|
NULLABLE_TYPE_LENGTH = 2 # Number of types in a nullable union (the type itself + null)
|
||||||
|
|
||||||
|
|
||||||
def create_tool_coroutine(tool_name: str, arg_schema: type[BaseModel], session) -> Callable[..., Awaitable]:
|
def create_tool_coroutine(tool_name: str, arg_schema: type[BaseModel], session) -> Callable[..., Awaitable]:
|
||||||
|
|
@ -107,15 +108,36 @@ def create_input_schema_from_json_schema(schema: dict[str, Any]) -> type[BaseMod
|
||||||
s = resolve_ref(s)
|
s = resolve_ref(s)
|
||||||
|
|
||||||
if "anyOf" in s:
|
if "anyOf" in s:
|
||||||
subtypes = [parse_type(sub) for sub in s["anyOf"]]
|
# Handle common pattern for nullable types (anyOf with string and null)
|
||||||
return tuple | subtypes
|
subtypes = [sub.get("type") for sub in s["anyOf"] if isinstance(sub, dict) and "type" in sub]
|
||||||
|
|
||||||
t = s.get("type", Any)
|
# Check if this is a simple nullable type (e.g., str | None)
|
||||||
|
if len(subtypes) == NULLABLE_TYPE_LENGTH and "null" in subtypes:
|
||||||
|
# Get the non-null type
|
||||||
|
non_null_type = next(t for t in subtypes if t != "null")
|
||||||
|
# Map it to Python type
|
||||||
|
if isinstance(non_null_type, str):
|
||||||
|
return {
|
||||||
|
"string": str,
|
||||||
|
"integer": int,
|
||||||
|
"number": float,
|
||||||
|
"boolean": bool,
|
||||||
|
"object": dict,
|
||||||
|
"array": list,
|
||||||
|
}.get(non_null_type, Any)
|
||||||
|
return Any
|
||||||
|
|
||||||
|
# For other anyOf cases, use the first non-null type
|
||||||
|
subtypes = [parse_type(sub) for sub in s["anyOf"]]
|
||||||
|
non_null_types = [t for t in subtypes if t is not None and t is not type(None)]
|
||||||
|
if non_null_types:
|
||||||
|
return non_null_types[0]
|
||||||
|
return str
|
||||||
|
|
||||||
|
t = s.get("type", "any") # Use string "any" as default instead of Any type
|
||||||
if t == "array":
|
if t == "array":
|
||||||
item_schema = s.get("items", {})
|
item_schema = s.get("items", {})
|
||||||
# schema_type: type[Any]
|
|
||||||
schema_type: Any = parse_type(item_schema)
|
schema_type: Any = parse_type(item_schema)
|
||||||
|
|
||||||
return list[schema_type]
|
return list[schema_type]
|
||||||
|
|
||||||
if t == "object":
|
if t == "object":
|
||||||
|
|
@ -131,9 +153,6 @@ def create_input_schema_from_json_schema(schema: dict[str, Any]) -> type[BaseMod
|
||||||
"object": dict,
|
"object": dict,
|
||||||
"array": list,
|
"array": list,
|
||||||
}.get(t, Any)
|
}.get(t, Any)
|
||||||
# if result == "":
|
|
||||||
# return Any
|
|
||||||
# return result
|
|
||||||
|
|
||||||
def _build_model(name: str, subschema: dict[str, Any]) -> type[BaseModel]:
|
def _build_model(name: str, subschema: dict[str, Any]) -> type[BaseModel]:
|
||||||
"""Create (or fetch) a BaseModel subclass for the given object schema."""
|
"""Create (or fetch) a BaseModel subclass for the given object schema."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue