fix: normalize json_schema from string to dict in VariableEntity (#36777)

This commit is contained in:
Evan 2026-06-03 12:33:25 +08:00 committed by GitHub
parent 1e76b9e1b8
commit 5a0ad4ecd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 105 additions and 0 deletions

View File

@ -1,4 +1,6 @@
import json
import re
from typing import Any
from core.app.app_config.entities import RagPipelineVariableEntity
from graphon.variables.input_entities import VariableEntity
@ -20,10 +22,32 @@ class WorkflowVariablesConfigManager:
# variables
for variable in user_input_form:
cls._normalize_json_schema(variable)
variables.append(VariableEntity.model_validate(variable))
return variables
@staticmethod
def _normalize_json_schema(variable: dict[str, Any]) -> None:
"""
Normalize ``json_schema`` from a JSON string to a dict.
The workflow graph is stored as JSON in the database. When a JSON
object variable carries a ``json_schema`` field, nested dicts are
preserved correctly, but older data or certain serialization paths
may store it as a JSON *string* instead of a native dict.
``VariableEntity.json_schema`` expects ``dict | None``, so we
deserialize the string here before handing it to Pydantic.
"""
json_schema = variable.get("json_schema")
if isinstance(json_schema, str):
try:
variable["json_schema"] = json.loads(json_schema)
except (json.JSONDecodeError, TypeError):
# Leave as-is; Pydantic validation will surface the error.
pass
@classmethod
def convert_rag_pipeline_variable(cls, workflow: Workflow, start_node_id: str) -> list[RagPipelineVariableEntity]:
"""

View File

@ -74,6 +74,87 @@ class TestWorkflowVariablesConfigManagerConvert:
with pytest.raises(ValueError):
WorkflowVariablesConfigManager.convert(mock_workflow)
def test_convert_normalizes_json_schema_string_to_dict(self, mock_workflow, mock_variable_entity):
"""Regression test for #36766: json_schema stored as a JSON string."""
import json
schema_dict = {"type": "object", "properties": {"name": {"type": "string"}}}
input_variables = [
{
"variable": "profile",
"label": "Profile",
"type": "json_object",
"json_schema": json.dumps(schema_dict),
}
]
mock_workflow.user_input_form.return_value = input_variables
mock_variable_entity.model_validate.side_effect = lambda x: x
# Act
result = WorkflowVariablesConfigManager.convert(mock_workflow)
# Assert — the string was deserialized before reaching model_validate
assert result[0]["json_schema"] == schema_dict
assert isinstance(result[0]["json_schema"], dict)
def test_convert_normalizes_json_schema_dict_passthrough(self, mock_workflow, mock_variable_entity):
"""json_schema already a dict should pass through unchanged."""
schema_dict = {"type": "object", "properties": {"age": {"type": "number"}}}
input_variables = [
{
"variable": "profile",
"label": "Profile",
"type": "json_object",
"json_schema": schema_dict,
}
]
mock_workflow.user_input_form.return_value = input_variables
mock_variable_entity.model_validate.side_effect = lambda x: x
# Act
result = WorkflowVariablesConfigManager.convert(mock_workflow)
# Assert
assert result[0]["json_schema"] == schema_dict
def test_convert_normalizes_json_schema_none_passthrough(self, mock_workflow, mock_variable_entity):
"""json_schema=None should pass through unchanged."""
input_variables = [
{
"variable": "name",
"label": "Name",
"type": "text-input",
"json_schema": None,
}
]
mock_workflow.user_input_form.return_value = input_variables
mock_variable_entity.model_validate.side_effect = lambda x: x
# Act
result = WorkflowVariablesConfigManager.convert(mock_workflow)
# Assert
assert result[0]["json_schema"] is None
def test_convert_normalizes_json_schema_invalid_string_passthrough(self, mock_workflow, mock_variable_entity):
"""Invalid JSON string should be left as-is for Pydantic to reject."""
input_variables = [
{
"variable": "profile",
"label": "Profile",
"type": "json_object",
"json_schema": "{invalid-json",
}
]
mock_workflow.user_input_form.return_value = input_variables
mock_variable_entity.model_validate.side_effect = lambda x: x
# Act
result = WorkflowVariablesConfigManager.convert(mock_workflow)
# Assert — string left as-is
assert result[0]["json_schema"] == "{invalid-json"
# =============================
# Test convert_rag_pipeline_variable