schemas.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from ast import literal_eval
  2. from typing import Any, Literal, Optional, Type
  3. from pydantic import BaseModel, Field, create_model
  4. def json_schema_to_model(tool_dict: dict[str, Any]) -> Type[BaseModel]:
  5. """
  6. Converts a JSON schema to a Pydantic BaseModel class.
  7. Args:
  8. json_schema: The JSON schema to convert.
  9. Returns:
  10. A Pydantic BaseModel class.
  11. """
  12. # Extract the model name from the schema title.
  13. model_name = tool_dict["name"]
  14. schema = tool_dict["parameters"]
  15. # Extract the field definitions from the schema properties.
  16. field_definitions = {
  17. name: json_schema_to_pydantic_field(name, prop, schema.get("required", []))
  18. for name, prop in schema.get("properties", {}).items()
  19. }
  20. # Create the BaseModel class using create_model().
  21. return create_model(model_name, **field_definitions)
  22. def json_schema_to_pydantic_field(
  23. name: str, json_schema: dict[str, Any], required: list[str]
  24. ) -> Any:
  25. """
  26. Converts a JSON schema property to a Pydantic field definition.
  27. Args:
  28. name: The field name.
  29. json_schema: The JSON schema property.
  30. Returns:
  31. A Pydantic field definition.
  32. """
  33. # Get the field type.
  34. type_ = json_schema_to_pydantic_type(json_schema)
  35. # Get the field description.
  36. description = json_schema.get("description")
  37. # Get the field examples.
  38. examples = json_schema.get("examples")
  39. # Create a Field object with the type, description, and examples.
  40. # The 'required' flag will be set later when creating the model.
  41. return (
  42. type_,
  43. Field(
  44. description=description,
  45. examples=examples,
  46. default=... if name in required else None,
  47. ),
  48. )
  49. def json_schema_to_pydantic_type(json_schema: dict[str, Any]) -> Any:
  50. """
  51. Converts a JSON schema type to a Pydantic type.
  52. Args:
  53. json_schema: The JSON schema to convert.
  54. Returns:
  55. A Pydantic type.
  56. """
  57. type_ = json_schema.get("type")
  58. if type_ == "string" or type_ == "str":
  59. return str
  60. elif type_ == "integer" or type_ == "int":
  61. return int
  62. elif type_ == "number" or type_ == "float":
  63. return float
  64. elif type_ == "boolean" or type_ == "bool":
  65. return bool
  66. elif type_ == "array" or type_ == "list":
  67. items_schema = json_schema.get("items")
  68. if items_schema:
  69. item_type = json_schema_to_pydantic_type(items_schema)
  70. return list[item_type]
  71. else:
  72. return list
  73. elif type_ == "object":
  74. # Handle nested models.
  75. properties = json_schema.get("properties")
  76. if properties:
  77. nested_model = json_schema_to_model(json_schema)
  78. return nested_model
  79. else:
  80. return dict
  81. elif type_ == "null":
  82. return Optional[Any] # Use Optional[Any] for nullable fields
  83. elif type_ == "literal":
  84. enum = json_schema.get("enum")
  85. if enum is None:
  86. raise ValueError("Enum values must be provided for 'literal' type.")
  87. return Literal[literal_eval(enum)]
  88. elif type_ == "optional":
  89. inner_schema = json_schema.get("items", {"type": "string"})
  90. inner_type = json_schema_to_pydantic_type(inner_schema)
  91. return Optional[inner_type]
  92. else:
  93. raise ValueError(f"Unsupported JSON schema type: {type_}")