|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- import re
- from typing import Any, Optional
-
- from core.schemas.registry import SchemaRegistry
-
-
- def resolve_dify_schema_refs(schema: Any, registry: Optional[SchemaRegistry] = None, max_depth: int = 10) -> Any:
- """
- Resolve $ref references in Dify schema to actual schema content
-
- Args:
- schema: Schema object that may contain $ref references
- registry: Optional schema registry, defaults to default registry
- max_depth: Maximum recursion depth to prevent infinite loops (default: 10)
-
- Returns:
- Schema with all $ref references resolved to actual content
-
- Raises:
- RecursionError: If maximum recursion depth is exceeded
- """
- if registry is None:
- registry = SchemaRegistry.default_registry()
-
- return _resolve_refs_recursive(schema, registry, max_depth, 0)
-
-
- def _resolve_refs_recursive(schema: Any, registry: SchemaRegistry, max_depth: int, current_depth: int) -> Any:
- """
- Recursively resolve $ref references in schema
-
- Args:
- schema: Schema object to process
- registry: Schema registry for lookups
- max_depth: Maximum allowed recursion depth
- current_depth: Current recursion depth
-
- Returns:
- Schema with references resolved
-
- Raises:
- RecursionError: If maximum depth exceeded
- """
- # Check recursion depth
- if current_depth >= max_depth:
- raise RecursionError(f"Maximum recursion depth ({max_depth}) exceeded while resolving schema references")
-
- if isinstance(schema, dict):
- # Check if this is a $ref reference
- if "$ref" in schema:
- ref_uri = schema["$ref"]
-
- # Only resolve Dify schema references
- if _is_dify_schema_ref(ref_uri):
- resolved_schema = registry.get_schema(ref_uri)
- if resolved_schema:
- # Remove metadata fields from resolved schema
- cleaned_schema = _remove_metadata_fields(resolved_schema)
- # Recursively resolve the cleaned schema in case it contains more refs
- return _resolve_refs_recursive(cleaned_schema, registry, max_depth, current_depth + 1)
- else:
- # If schema not found, return original ref (might be external or invalid)
- return schema
- else:
- # Non-Dify reference, return as-is
- return schema
- else:
- # Regular dict, recursively process all values
- resolved_dict = {}
- for key, value in schema.items():
- resolved_dict[key] = _resolve_refs_recursive(value, registry, max_depth, current_depth + 1)
- return resolved_dict
-
- elif isinstance(schema, list):
- # Process list items recursively
- return [_resolve_refs_recursive(item, registry, max_depth, current_depth + 1) for item in schema]
-
- else:
- # Primitive value, return as-is
- return schema
-
-
- def _remove_metadata_fields(schema: dict) -> dict:
- """
- Remove metadata fields from schema that shouldn't be included in resolved output
- """
- if not isinstance(schema, dict):
- return schema
-
- # Create a copy and remove metadata fields
- cleaned = schema.copy()
- metadata_fields = ["$id", "$schema", "version"]
-
- for field in metadata_fields:
- cleaned.pop(field, None)
-
- return cleaned
-
-
- def _is_dify_schema_ref(ref_uri: str) -> bool:
- """
- Check if the reference URI is a Dify schema reference
- """
- if not isinstance(ref_uri, str):
- return False
-
- # Match Dify schema URI pattern: https://dify.ai/schemas/v*/name.json
- pattern = r"^https://dify\.ai/schemas/(v\d+)/(.+)\.json$"
- return bool(re.match(pattern, ref_uri))
|