#23094·llama_index

[Bug]: DashScope FunctionTool conversion drops nested JSON Schema definitions

Author: GYWang1983Created Sep 17, 2026Updated Sep 17, 2026

Bug description

llama-index-llms-dashscope==0.7.0 corrupts valid nested JSON Schema when it converts a FunctionTool for DashScope.

DashScope._convert_tool_to_dashscope_format() retains only type and properties from tool.metadata.get_parameters_dict(). For Pydantic schemas with nested models, this removes root $defs but leaves items.$ref pointing to it. It also puts required under function, instead of under function.parameters.

This makes the wire-schema internally inconsistent and weakens tool-argument constraints. Agent traces that record tool.metadata.to_openai_tool() can look valid even though the adapter sends the damaged version.

Version

  • llama-index-llms-dashscope==0.7.0
  • llama-index-core==0.14.24 (resolved by an isolated uv run --no-project --with ... environment)
  • Python 3.14

Minimal reproduction

from pydantic import BaseModel, Field
from jsonschema import Draft202012Validator
from llama_index.core.tools import FunctionTool
from llama_index.llms.dashscope import DashScope


class Item(BaseModel):
    entity: str
    entity_type: str


class Batch(BaseModel):
    entities: list[Item] = Field(max_length=128)


def validate_entities(entities: list[Item]) -> str:
    return "ok"


tool = FunctionTool.from_defaults(fn=validate_entities, fn_schema=Batch)
original = tool.metadata.get_parameters_dict()
converted = DashScope._convert_tool_to_dashscope_format(None, tool)
arguments = {"entities": [{"entity": "Example", "entity_type": "Organization"}]}

print(sorted(original))
print(sorted(converted["function"]["parameters"]))
print(converted["function"].get("required"))
print(list(Draft202012Validator(original).iter_errors(arguments)))
print(list(Draft202012Validator(converted["function"]["parameters"]).iter_errors(arguments)))

Observed output before the final line raises:

['$defs', 'properties', 'required', 'type']
['properties', 'type']
['entities']
[]
jsonschema.exceptions._WrappedReferencingError:
PointerToNowhere: '/$defs/Item' does not exist within
{'type': 'object', 'properties': {'entities': {'items': {'$ref': '#/$defs/Item'}, ...}}}

Expected behavior

The converted function.parameters should remain a valid schema. At minimum it should preserve $defs together with $ref, and place required inside parameters:

parameters = tool.metadata.get_parameters_dict()
tool_spec = {
    "type": "function",
    "function": {
        "name": tool.metadata.name,
        "description": tool.metadata.description,
        "parameters": parameters,
    },
}

If the target DashScope endpoint cannot accept $defs/$ref, the adapter should inline or otherwise resolve references before sending the request, with tests for nested Pydantic schemas. A regression test should validate the outgoing schema, not only ToolMetadata.to_openai_tool().

I found related DashScope tool-call issues but no existing issue covering this $defs/$ref plus misplaced-required conversion defect.