diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 707b28e6d8..4f659c5e13 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -55,8 +55,8 @@ def init_code_node(code_config: dict): environment_variables=[], conversation_variables=[], ) - variable_pool.add(["code", "123", "args1"], 1) - variable_pool.add(["code", "123", "args2"], 2) + variable_pool.add(["code", "args1"], 1) + variable_pool.add(["code", "args2"], 2) node = CodeNode( id=str(uuid.uuid4()), @@ -96,9 +96,9 @@ def test_execute_code(setup_code_executor_mock): "variables": [ { "variable": "args1", - "value_selector": ["1", "123", "args1"], + "value_selector": ["1", "args1"], }, - {"variable": "args2", "value_selector": ["1", "123", "args2"]}, + {"variable": "args2", "value_selector": ["1", "args2"]}, ], "answer": "123", "code_language": "python3", @@ -107,8 +107,8 @@ def test_execute_code(setup_code_executor_mock): } node = init_code_node(code_config) - node.graph_runtime_state.variable_pool.add(["1", "123", "args1"], 1) - node.graph_runtime_state.variable_pool.add(["1", "123", "args2"], 2) + node.graph_runtime_state.variable_pool.add(["1", "args1"], 1) + node.graph_runtime_state.variable_pool.add(["1", "args2"], 2) # execute node result = node._run() @@ -142,9 +142,9 @@ def test_execute_code_output_validator(setup_code_executor_mock): "variables": [ { "variable": "args1", - "value_selector": ["1", "123", "args1"], + "value_selector": ["1", "args1"], }, - {"variable": "args2", "value_selector": ["1", "123", "args2"]}, + {"variable": "args2", "value_selector": ["1", "args2"]}, ], "answer": "123", "code_language": "python3", @@ -153,8 +153,8 @@ def test_execute_code_output_validator(setup_code_executor_mock): } node = init_code_node(code_config) - node.graph_runtime_state.variable_pool.add(["1", "123", "args1"], 1) - node.graph_runtime_state.variable_pool.add(["1", "123", "args2"], 2) + node.graph_runtime_state.variable_pool.add(["1", "args1"], 1) + node.graph_runtime_state.variable_pool.add(["1", "args2"], 2) # execute node result = node._run() @@ -217,9 +217,9 @@ def test_execute_code_output_validator_depth(): "variables": [ { "variable": "args1", - "value_selector": ["1", "123", "args1"], + "value_selector": ["1", "args1"], }, - {"variable": "args2", "value_selector": ["1", "123", "args2"]}, + {"variable": "args2", "value_selector": ["1", "args2"]}, ], "answer": "123", "code_language": "python3", @@ -307,9 +307,9 @@ def test_execute_code_output_object_list(): "variables": [ { "variable": "args1", - "value_selector": ["1", "123", "args1"], + "value_selector": ["1", "args1"], }, - {"variable": "args2", "value_selector": ["1", "123", "args2"]}, + {"variable": "args2", "value_selector": ["1", "args2"]}, ], "answer": "123", "code_language": "python3", diff --git a/api/tests/integration_tests/workflow/nodes/test_http.py b/api/tests/integration_tests/workflow/nodes/test_http.py index d7856129a3..344539d51a 100644 --- a/api/tests/integration_tests/workflow/nodes/test_http.py +++ b/api/tests/integration_tests/workflow/nodes/test_http.py @@ -49,8 +49,8 @@ def init_http_node(config: dict): environment_variables=[], conversation_variables=[], ) - variable_pool.add(["a", "b123", "args1"], 1) - variable_pool.add(["a", "b123", "args2"], 2) + variable_pool.add(["a", "args1"], 1) + variable_pool.add(["a", "args2"], 2) node = HttpRequestNode( id=str(uuid.uuid4()), @@ -171,7 +171,7 @@ def test_template(setup_http_mock): "title": "http", "desc": "", "method": "get", - "url": "http://example.com/{{#a.b123.args2#}}", + "url": "http://example.com/{{#a.args2#}}", "authorization": { "type": "api-key", "config": { @@ -180,8 +180,8 @@ def test_template(setup_http_mock): "header": "api-key", }, }, - "headers": "X-Header:123\nX-Header2:{{#a.b123.args2#}}", - "params": "A:b\nTemplate:{{#a.b123.args2#}}", + "headers": "X-Header:123\nX-Header2:{{#a.args2#}}", + "params": "A:b\nTemplate:{{#a.args2#}}", "body": None, }, } @@ -223,7 +223,7 @@ def test_json(setup_http_mock): { "key": "", "type": "text", - "value": '{"a": "{{#a.b123.args1#}}"}', + "value": '{"a": "{{#a.args1#}}"}', }, ], }, @@ -264,12 +264,12 @@ def test_x_www_form_urlencoded(setup_http_mock): { "key": "a", "type": "text", - "value": "{{#a.b123.args1#}}", + "value": "{{#a.args1#}}", }, { "key": "b", "type": "text", - "value": "{{#a.b123.args2#}}", + "value": "{{#a.args2#}}", }, ], }, @@ -310,12 +310,12 @@ def test_form_data(setup_http_mock): { "key": "a", "type": "text", - "value": "{{#a.b123.args1#}}", + "value": "{{#a.args1#}}", }, { "key": "b", "type": "text", - "value": "{{#a.b123.args2#}}", + "value": "{{#a.args2#}}", }, ], }, @@ -436,3 +436,87 @@ def test_multi_colons_parse(setup_http_mock): assert 'form-data; name="Redirect"\r\n\r\nhttp://example6.com' in result.process_data.get("request", "") # resp = result.outputs # assert "http://example3.com" == resp.get("headers", {}).get("referer") + + +@pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True) +def test_nested_object_variable_selector(setup_http_mock): + """Test variable selector functionality with nested object properties.""" + # Create independent test setup without affecting other tests + graph_config = { + "edges": [ + { + "id": "start-source-next-target", + "source": "start", + "target": "1", + }, + ], + "nodes": [ + {"data": {"type": "start"}, "id": "start"}, + { + "id": "1", + "data": { + "title": "http", + "desc": "", + "method": "get", + "url": "http://example.com/{{#a.args2#}}/{{#a.args3.nested#}}", + "authorization": { + "type": "api-key", + "config": { + "type": "basic", + "api_key": "ak-xxx", + "header": "api-key", + }, + }, + "headers": "X-Header:{{#a.args3.nested#}}", + "params": "nested_param:{{#a.args3.nested#}}", + "body": None, + }, + }, + ], + } + + graph = Graph.init(graph_config=graph_config) + + init_params = GraphInitParams( + tenant_id="1", + app_id="1", + workflow_type=WorkflowType.WORKFLOW, + workflow_id="1", + graph_config=graph_config, + user_id="1", + user_from=UserFrom.ACCOUNT, + invoke_from=InvokeFrom.DEBUGGER, + call_depth=0, + ) + + # Create independent variable pool for this test only + variable_pool = VariablePool( + system_variables=SystemVariable(user_id="aaa", files=[]), + user_inputs={}, + environment_variables=[], + conversation_variables=[], + ) + variable_pool.add(["a", "args1"], 1) + variable_pool.add(["a", "args2"], 2) + variable_pool.add(["a", "args3"], {"nested": "nested_value"}) # Only for this test + + node = HttpRequestNode( + id=str(uuid.uuid4()), + graph_init_params=init_params, + graph=graph, + graph_runtime_state=GraphRuntimeState(variable_pool=variable_pool, start_at=time.perf_counter()), + config=graph_config["nodes"][1], + ) + + # Initialize node data + if "data" in graph_config["nodes"][1]: + node.init_node_data(graph_config["nodes"][1]["data"]) + + result = node._run() + assert result.process_data is not None + data = result.process_data.get("request", "") + + # Verify nested object property is correctly resolved + assert "/2/nested_value" in data # URL path should contain resolved nested value + assert "X-Header: nested_value" in data # Header should contain nested value + assert "nested_param=nested_value" in data # Param should contain nested value diff --git a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py index edd70193a8..ef373d968d 100644 --- a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py +++ b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py @@ -71,8 +71,8 @@ def init_parameter_extractor_node(config: dict): environment_variables=[], conversation_variables=[], ) - variable_pool.add(["a", "b123", "args1"], 1) - variable_pool.add(["a", "b123", "args2"], 2) + variable_pool.add(["a", "args1"], 1) + variable_pool.add(["a", "args2"], 2) node = ParameterExtractorNode( id=str(uuid.uuid4()), diff --git a/api/tests/integration_tests/workflow/nodes/test_template_transform.py b/api/tests/integration_tests/workflow/nodes/test_template_transform.py index f71a5ee140..56265c6b95 100644 --- a/api/tests/integration_tests/workflow/nodes/test_template_transform.py +++ b/api/tests/integration_tests/workflow/nodes/test_template_transform.py @@ -26,9 +26,9 @@ def test_execute_code(setup_code_executor_mock): "variables": [ { "variable": "args1", - "value_selector": ["1", "123", "args1"], + "value_selector": ["1", "args1"], }, - {"variable": "args2", "value_selector": ["1", "123", "args2"]}, + {"variable": "args2", "value_selector": ["1", "args2"]}, ], "template": code, }, @@ -66,8 +66,8 @@ def test_execute_code(setup_code_executor_mock): environment_variables=[], conversation_variables=[], ) - variable_pool.add(["1", "123", "args1"], 1) - variable_pool.add(["1", "123", "args2"], 3) + variable_pool.add(["1", "args1"], 1) + variable_pool.add(["1", "args2"], 3) node = TemplateTransformNode( id=str(uuid.uuid4()), diff --git a/api/tests/integration_tests/workflow/nodes/test_tool.py b/api/tests/integration_tests/workflow/nodes/test_tool.py index 8476c1f874..19a9b36350 100644 --- a/api/tests/integration_tests/workflow/nodes/test_tool.py +++ b/api/tests/integration_tests/workflow/nodes/test_tool.py @@ -81,7 +81,7 @@ def test_tool_variable_invoke(): ToolParameterConfigurationManager.decrypt_tool_parameters = MagicMock(return_value={"format": "%Y-%m-%d %H:%M:%S"}) - node.graph_runtime_state.variable_pool.add(["1", "123", "args1"], "1+1") + node.graph_runtime_state.variable_pool.add(["1", "args1"], "1+1") # execute node result = node._run()