test(core): add regression test for list-index $ref resolution (#34097)

This PR adds a regression test covering the JSON Schema `$ref` pattern
found in
MCP-style schemas, where a `$ref` points into a list-based structure
such as:


#/properties/body/anyOf/1/properties/Message/properties/bccRecipients/items

This pattern historically failed due to incorrect handling of numeric
list
components in `_retrieve_ref`. The underlying bug has since been fixed,
and
this test ensures coverage so we don't regress on list-index `$ref`
resolution.

The new test (`test_dereference_refs_list_index_items_ref_mcp_like`)
verifies:

- correct traversal into `anyOf[1]`
- proper dereferencing of `items.$ref`
- no errors thrown
- `ccRecipients.items` is identical to the resolved schema of
`bccRecipients.items`

No code changes are included, just the one test — this PR adds coverage
to preserve the expected
behavior and documents support for this real-world MCP schema pattern.

Related to #32012.

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
Miguel Athie
2025-12-27 02:18:51 -06:00
committed by GitHub
parent ca7790f895
commit b0e4ef3158

View File

@@ -452,6 +452,84 @@ def test_dereference_refs_list_index() -> None:
assert actual_dict_key == expected_dict_key
def test_dereference_refs_list_index_items_ref_mcp_like() -> None:
"""Regression test: MCP-style list index ref into array items."""
schema = {
"type": "object",
"properties": {
"body": {
"anyOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"Message": {
"type": "object",
"properties": {
"bccRecipients": {
"type": "array",
"items": {
"type": "object",
"properties": {
"emailAddress": {
"type": "object",
"properties": {
"address": {"type": "string"},
"name": {"type": "string"},
},
"required": ["address"],
}
},
},
"description": (
"The Bcc: recipients for the message."
),
},
"ccRecipients": {
"type": "array",
"items": {
"$ref": (
"#/properties/body/anyOf/1/"
"properties/Message/properties/"
"bccRecipients/items"
)
},
"description": (
"The Cc: recipients for the message."
),
},
},
"additionalProperties": False,
},
"SaveToSentItems": {
"type": ["boolean", "null"],
"default": False,
},
},
"additionalProperties": False,
},
]
}
},
"required": ["body"],
"additionalProperties": False,
}
resolved = dereference_refs(schema)
message_props = resolved["properties"]["body"]["anyOf"][1]["properties"]["Message"][
"properties"
]
bcc_items = message_props["bccRecipients"]["items"]
cc_items = message_props["ccRecipients"]["items"]
# $ref should be fully resolved in ccRecipients.items
assert "$ref" not in cc_items
# And ccRecipients.items should match bccRecipients.items
assert cc_items == bcc_items
def test_dereference_refs_mixed_ref_with_properties() -> None:
"""Test dereferencing refs that have $ref plus other properties."""
# This pattern can cause infinite recursion if not handled correctly