您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

resolver.py 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import re
  2. from typing import Any, Optional
  3. from core.schemas.registry import SchemaRegistry
  4. def resolve_dify_schema_refs(schema: Any, registry: Optional[SchemaRegistry] = None, max_depth: int = 10) -> Any:
  5. """
  6. Resolve $ref references in Dify schema to actual schema content
  7. Args:
  8. schema: Schema object that may contain $ref references
  9. registry: Optional schema registry, defaults to default registry
  10. max_depth: Maximum recursion depth to prevent infinite loops (default: 10)
  11. Returns:
  12. Schema with all $ref references resolved to actual content
  13. Raises:
  14. RecursionError: If maximum recursion depth is exceeded
  15. """
  16. if registry is None:
  17. registry = SchemaRegistry.default_registry()
  18. return _resolve_refs_recursive(schema, registry, max_depth, 0)
  19. def _resolve_refs_recursive(schema: Any, registry: SchemaRegistry, max_depth: int, current_depth: int) -> Any:
  20. """
  21. Recursively resolve $ref references in schema
  22. Args:
  23. schema: Schema object to process
  24. registry: Schema registry for lookups
  25. max_depth: Maximum allowed recursion depth
  26. current_depth: Current recursion depth
  27. Returns:
  28. Schema with references resolved
  29. Raises:
  30. RecursionError: If maximum depth exceeded
  31. """
  32. # Check recursion depth
  33. if current_depth >= max_depth:
  34. raise RecursionError(f"Maximum recursion depth ({max_depth}) exceeded while resolving schema references")
  35. if isinstance(schema, dict):
  36. # Check if this is a $ref reference
  37. if "$ref" in schema:
  38. ref_uri = schema["$ref"]
  39. # Only resolve Dify schema references
  40. if _is_dify_schema_ref(ref_uri):
  41. resolved_schema = registry.get_schema(ref_uri)
  42. if resolved_schema:
  43. # Remove metadata fields from resolved schema
  44. cleaned_schema = _remove_metadata_fields(resolved_schema)
  45. # Recursively resolve the cleaned schema in case it contains more refs
  46. return _resolve_refs_recursive(cleaned_schema, registry, max_depth, current_depth + 1)
  47. else:
  48. # If schema not found, return original ref (might be external or invalid)
  49. return schema
  50. else:
  51. # Non-Dify reference, return as-is
  52. return schema
  53. else:
  54. # Regular dict, recursively process all values
  55. resolved_dict = {}
  56. for key, value in schema.items():
  57. resolved_dict[key] = _resolve_refs_recursive(value, registry, max_depth, current_depth + 1)
  58. return resolved_dict
  59. elif isinstance(schema, list):
  60. # Process list items recursively
  61. return [_resolve_refs_recursive(item, registry, max_depth, current_depth + 1) for item in schema]
  62. else:
  63. # Primitive value, return as-is
  64. return schema
  65. def _remove_metadata_fields(schema: dict) -> dict:
  66. """
  67. Remove metadata fields from schema that shouldn't be included in resolved output
  68. """
  69. if not isinstance(schema, dict):
  70. return schema
  71. # Create a copy and remove metadata fields
  72. cleaned = schema.copy()
  73. metadata_fields = ["$id", "$schema", "version"]
  74. for field in metadata_fields:
  75. cleaned.pop(field, None)
  76. return cleaned
  77. def _is_dify_schema_ref(ref_uri: str) -> bool:
  78. """
  79. Check if the reference URI is a Dify schema reference
  80. """
  81. if not isinstance(ref_uri, str):
  82. return False
  83. # Match Dify schema URI pattern: https://dify.ai/schemas/v*/name.json
  84. pattern = r"^https://dify\.ai/schemas/(v\d+)/(.+)\.json$"
  85. return bool(re.match(pattern, ref_uri))