mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-12-03 09:53:45 +00:00
chore: fix missing titles for unions
Added _add_titles_to_unions() to: Recursively scan all schemas for anyOf/oneOf unions Generate descriptive titles from the union members Add those titles to help code generators infer names Signed-off-by: Sébastien Han <seb@redhat.com>
This commit is contained in:
parent
500804f0eb
commit
221f28b685
6 changed files with 3404 additions and 1663 deletions
File diff suppressed because it is too large
Load diff
1122
docs/static/deprecated-llama-stack-spec.yaml
vendored
1122
docs/static/deprecated-llama-stack-spec.yaml
vendored
File diff suppressed because it is too large
Load diff
909
docs/static/experimental-llama-stack-spec.yaml
vendored
909
docs/static/experimental-llama-stack-spec.yaml
vendored
File diff suppressed because it is too large
Load diff
1030
docs/static/llama-stack-spec.yaml
vendored
1030
docs/static/llama-stack-spec.yaml
vendored
File diff suppressed because it is too large
Load diff
988
docs/static/stainless-llama-stack-spec.yaml
vendored
988
docs/static/stainless-llama-stack-spec.yaml
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1030,10 +1030,11 @@ def _fix_path_parameters(openapi_schema: dict[str, Any]) -> dict[str, Any]:
|
|||
|
||||
|
||||
def _fix_schema_issues(openapi_schema: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Fix common schema issues: exclusiveMinimum and null defaults."""
|
||||
"""Fix common schema issues: exclusiveMinimum, null defaults, and add titles to unions."""
|
||||
if "components" in openapi_schema and "schemas" in openapi_schema["components"]:
|
||||
for schema_def in openapi_schema["components"]["schemas"].values():
|
||||
for schema_name, schema_def in openapi_schema["components"]["schemas"].items():
|
||||
_fix_schema_recursive(schema_def)
|
||||
_add_titles_to_unions(schema_def, schema_name)
|
||||
return openapi_schema
|
||||
|
||||
|
||||
|
|
@ -1064,6 +1065,130 @@ def validate_openapi_schema(schema: dict[str, Any], schema_name: str = "OpenAPI
|
|||
return False
|
||||
|
||||
|
||||
def _get_schema_title(item: dict[str, Any]) -> str | None:
|
||||
"""Extract a title for a schema item to use in union variant names."""
|
||||
if "$ref" in item:
|
||||
return item["$ref"].split("/")[-1]
|
||||
elif "type" in item:
|
||||
type_val = item["type"]
|
||||
if type_val == "null":
|
||||
return None
|
||||
if type_val == "array" and "items" in item:
|
||||
items = item["items"]
|
||||
if isinstance(items, dict):
|
||||
if "anyOf" in items or "oneOf" in items:
|
||||
nested_union = items.get("anyOf") or items.get("oneOf")
|
||||
if isinstance(nested_union, list) and len(nested_union) > 0:
|
||||
nested_types = []
|
||||
for nested_item in nested_union:
|
||||
if isinstance(nested_item, dict):
|
||||
if "$ref" in nested_item:
|
||||
nested_types.append(nested_item["$ref"].split("/")[-1])
|
||||
elif "oneOf" in nested_item:
|
||||
one_of_items = nested_item.get("oneOf", [])
|
||||
if one_of_items and isinstance(one_of_items[0], dict) and "$ref" in one_of_items[0]:
|
||||
base_name = one_of_items[0]["$ref"].split("/")[-1].split("-")[0]
|
||||
nested_types.append(f"{base_name}Union")
|
||||
else:
|
||||
nested_types.append("Union")
|
||||
elif "type" in nested_item and nested_item["type"] != "null":
|
||||
nested_types.append(nested_item["type"])
|
||||
if nested_types:
|
||||
unique_nested = list(dict.fromkeys(nested_types))
|
||||
# Use more descriptive names for better code generation
|
||||
if len(unique_nested) <= 3:
|
||||
return f"list[{' | '.join(unique_nested)}]"
|
||||
else:
|
||||
# Include first few types for better naming
|
||||
return f"list[{unique_nested[0]} | {unique_nested[1]} | ...]"
|
||||
return "list[Union]"
|
||||
elif "$ref" in items:
|
||||
return f"list[{items['$ref'].split('/')[-1]}]"
|
||||
elif "type" in items:
|
||||
return f"list[{items['type']}]"
|
||||
return "array"
|
||||
return type_val
|
||||
elif "title" in item:
|
||||
return item["title"]
|
||||
return None
|
||||
|
||||
|
||||
def _add_titles_to_unions(obj: Any, parent_key: str | None = None) -> None:
|
||||
"""Recursively add titles to union schemas (anyOf/oneOf) to help code generators infer names."""
|
||||
if isinstance(obj, dict):
|
||||
# Check if this is a union schema (anyOf or oneOf)
|
||||
if "anyOf" in obj or "oneOf" in obj:
|
||||
union_type = "anyOf" if "anyOf" in obj else "oneOf"
|
||||
union_items = obj[union_type]
|
||||
|
||||
if isinstance(union_items, list) and len(union_items) > 0:
|
||||
# Skip simple nullable unions (type | null) - these don't need titles
|
||||
is_simple_nullable = (
|
||||
len(union_items) == 2
|
||||
and any(isinstance(item, dict) and item.get("type") == "null" for item in union_items)
|
||||
and any(
|
||||
isinstance(item, dict) and "type" in item and item.get("type") != "null" for item in union_items
|
||||
)
|
||||
and not any(
|
||||
isinstance(item, dict) and ("$ref" in item or "anyOf" in item or "oneOf" in item)
|
||||
for item in union_items
|
||||
)
|
||||
)
|
||||
|
||||
if is_simple_nullable:
|
||||
# Remove title from simple nullable unions if it exists
|
||||
if "title" in obj:
|
||||
del obj["title"]
|
||||
else:
|
||||
# Add titles to individual union variants that need them
|
||||
for item in union_items:
|
||||
if isinstance(item, dict):
|
||||
# Skip null types
|
||||
if item.get("type") == "null":
|
||||
continue
|
||||
# Add title to complex variants (arrays with unions, nested unions, etc.)
|
||||
# Also add to simple types if they're part of a complex union
|
||||
needs_title = (
|
||||
"items" in item
|
||||
or "anyOf" in item
|
||||
or "oneOf" in item
|
||||
or ("$ref" in item and "title" not in item)
|
||||
)
|
||||
if needs_title and "title" not in item:
|
||||
variant_title = _get_schema_title(item)
|
||||
if variant_title:
|
||||
item["title"] = variant_title
|
||||
|
||||
# Try to infer a meaningful title from the union items for the parent
|
||||
titles = []
|
||||
for item in union_items:
|
||||
if isinstance(item, dict):
|
||||
title = _get_schema_title(item)
|
||||
if title:
|
||||
titles.append(title)
|
||||
|
||||
if titles:
|
||||
# Create a title from the union items
|
||||
unique_titles = list(dict.fromkeys(titles)) # Preserve order, remove duplicates
|
||||
if len(unique_titles) <= 3:
|
||||
title = " | ".join(unique_titles)
|
||||
else:
|
||||
title = f"{unique_titles[0]} | ... ({len(unique_titles)} variants)"
|
||||
# Always set the title for unions to help code generators
|
||||
# This will replace generic property titles with union-specific ones
|
||||
obj["title"] = title
|
||||
elif "title" not in obj and parent_key:
|
||||
# Use parent key as fallback only if no title exists
|
||||
obj["title"] = f"{parent_key.title()}Union"
|
||||
|
||||
# Recursively process all values
|
||||
for key, value in obj.items():
|
||||
_add_titles_to_unions(value, key)
|
||||
elif isinstance(obj, list):
|
||||
for item in obj:
|
||||
_add_titles_to_unions(item, parent_key)
|
||||
|
||||
|
||||
def _fix_schema_recursive(obj: Any) -> None:
|
||||
"""Recursively fix schema issues: exclusiveMinimum and null defaults."""
|
||||
if isinstance(obj, dict):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue