fix: resolve circular OpenAPI schema refs in tool server specs (#27413)

OpenAPI specs with circular schema references, such as Mealie's where Recipe and RecipeCategory reference each other through properties and array items, crashed convert_openapi_to_tool_payload with a RecursionError, so the tool server produced no specs and the integration never appeared in the model or tool selection. resolve_schema already had a visited-set guard against circular references, but the recursive calls for properties and items dropped the set, so cycles running through those edges were never detected. This threads the visited set through those calls and passes a per-path copy when following a $ref, so only true ancestor cycles are pruned to an empty schema while sibling references to the same schema still resolve fully. Fixes #27239.
This commit is contained in:
Classic298
2026-07-27 00:20:10 +02:00
committed by GitHub
parent 771540f3de
commit 301bf519ab

View File

@@ -913,23 +913,22 @@ def resolve_schema(schema, components, resolved_schemas=None):
# Avoid infinite recursion on circular references
return {}
resolved_schemas.add(schema_name)
ref_parts = ref_path.strip('#/').split('/')
resolved = components
for part in ref_parts[1:]: # Skip the initial 'components'
resolved = resolved.get(part, {})
return resolve_schema(resolved, components, resolved_schemas)
# Per-path visited set so sibling refs to the same schema still resolve
return resolve_schema(resolved, components, resolved_schemas | {schema_name})
resolved_schema = copy.deepcopy(schema)
# Recursively resolve inner schemas
if 'properties' in resolved_schema:
for prop, prop_schema in resolved_schema['properties'].items():
resolved_schema['properties'][prop] = resolve_schema(prop_schema, components)
resolved_schema['properties'][prop] = resolve_schema(prop_schema, components, resolved_schemas)
if 'items' in resolved_schema:
resolved_schema['items'] = resolve_schema(resolved_schema['items'], components)
resolved_schema['items'] = resolve_schema(resolved_schema['items'], components, resolved_schemas)
# Resolve composition keywords (oneOf, anyOf, allOf) which may contain $ref
for keyword in ('oneOf', 'anyOf', 'allOf'):