Test:Add multiple test cases to verify the correctness of different output configurations, including complex outputs and handling of missing variables.

pull/20921/head
GuanMu 8 months ago
parent 7dd1bf0597
commit 81027f6077

@ -196,7 +196,13 @@ class GraphEngine:
self.graph_runtime_state.outputs["answer"] = self.graph_runtime_state.outputs[
"answer"
].strip()
self.graph_runtime_state.outputs["outputs"] = item.route_node_state.node_run_result.outputs
# Only save the user-defined output variables, not the entire node output
if (item.route_node_state.node_run_result
and item.route_node_state.node_run_result.outputs
and "outputs" in item.route_node_state.node_run_result.outputs):
user_outputs = item.route_node_state.node_run_result.outputs.get("outputs", {})
self.graph_runtime_state.outputs.update(user_outputs)
except Exception as e:
logger.exception("Graph run failed")
yield GraphRunFailedEvent(error=str(e), exceptions_count=len(handle_exceptions))

@ -82,3 +82,374 @@ def test_execute_answer():
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
assert result.outputs["answer"] == "Today's weather is sunny\nYou are a helpful AI.\n{{img}}\nFin."
def test_execute_answer_with_outputs():
"""Test Answer node with custom output variables"""
graph_config = {
"edges": [
{
"id": "start-source-answer-target",
"source": "start",
"target": "answer",
},
],
"nodes": [
{"data": {"type": "start"}, "id": "start"},
{
"data": {
"title": "Answer with outputs",
"type": "answer",
"answer": "Weather: {{#start.weather#}}, Score: {{#start.score#}}",
"outputs": [
{
"variable": "confidence",
"type": "number",
"value_selector": ["start", "score"]
},
{
"variable": "status",
"type": "string",
"value_selector": ["start", "weather"]
}
],
},
"id": "answer",
},
],
}
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,
)
# construct variable pool
variable_pool = VariablePool(
system_variables={SystemVariableKey.FILES: [], SystemVariableKey.USER_ID: "aaa"},
user_inputs={},
environment_variables=[],
conversation_variables=[],
)
variable_pool.add(["start", "weather"], "sunny")
variable_pool.add(["start", "score"], 85)
node = AnswerNode(
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={
"id": "answer",
"data": {
"title": "Answer with outputs",
"type": "answer",
"answer": "Weather: {{#start.weather#}}, Score: {{#start.score#}}",
"outputs": [
{
"variable": "confidence",
"type": "number",
"value_selector": ["start", "score"]
},
{
"variable": "status",
"type": "string",
"value_selector": ["start", "weather"]
}
],
},
},
)
# Mock db.session.close()
db.session.close = MagicMock()
# execute node
result = node._run()
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
assert result.outputs is not None
assert result.outputs["answer"] == "Weather: sunny, Score: 85"
# Check outputs field
assert "outputs" in result.outputs
outputs = result.outputs["outputs"]
assert outputs["confidence"] == 85
assert outputs["status"] == "sunny"
def test_execute_answer_with_complex_outputs():
"""Test Answer node with complex output variables including arrays and objects"""
graph_config = {
"edges": [
{
"id": "start-source-answer-target",
"source": "start",
"target": "answer",
},
],
"nodes": [
{"data": {"type": "start"}, "id": "start"},
{
"data": {
"title": "Complex outputs",
"type": "answer",
"answer": "Analysis complete",
"outputs": [
{
"variable": "scores",
"type": "array[number]",
"value_selector": ["start", "score_list"]
},
{
"variable": "metadata",
"type": "object",
"value_selector": ["start", "meta_info"]
}
],
},
"id": "answer",
},
],
}
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,
)
# construct variable pool with complex data
variable_pool = VariablePool(
system_variables={SystemVariableKey.FILES: [], SystemVariableKey.USER_ID: "aaa"},
user_inputs={},
environment_variables=[],
conversation_variables=[],
)
variable_pool.add(["start", "score_list"], [85, 92, 78])
variable_pool.add(["start", "meta_info"], {"category": "test", "priority": "high"})
node = AnswerNode(
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={
"id": "answer",
"data": {
"title": "Complex outputs",
"type": "answer",
"answer": "Analysis complete",
"outputs": [
{
"variable": "scores",
"type": "array[number]",
"value_selector": ["start", "score_list"]
},
{
"variable": "metadata",
"type": "object",
"value_selector": ["start", "meta_info"]
}
],
},
},
)
# Mock db.session.close()
db.session.close = MagicMock()
# execute node
result = node._run()
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
assert result.outputs["answer"] == "Analysis complete"
# Check complex outputs
assert "outputs" in result.outputs
outputs = result.outputs["outputs"]
assert outputs["scores"] == [85, 92, 78]
assert outputs["metadata"] == {"category": "test", "priority": "high"}
def test_execute_answer_with_empty_outputs():
"""Test Answer node with empty outputs configuration"""
graph_config = {
"edges": [
{
"id": "start-source-answer-target",
"source": "start",
"target": "answer",
},
],
"nodes": [
{"data": {"type": "start"}, "id": "start"},
{
"data": {
"title": "No outputs",
"type": "answer",
"answer": "Simple answer",
"outputs": [],
},
"id": "answer",
},
],
}
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,
)
# construct variable pool
variable_pool = VariablePool(
system_variables={SystemVariableKey.FILES: [], SystemVariableKey.USER_ID: "aaa"},
user_inputs={},
environment_variables=[],
conversation_variables=[],
)
node = AnswerNode(
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={
"id": "answer",
"data": {
"title": "No outputs",
"type": "answer",
"answer": "Simple answer",
"outputs": [],
},
},
)
# Mock db.session.close()
db.session.close = MagicMock()
# execute node
result = node._run()
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
assert result.outputs["answer"] == "Simple answer"
# Check that outputs field is empty when no outputs are configured
assert "outputs" in result.outputs
assert result.outputs["outputs"] == {}
def test_execute_answer_outputs_variable_not_found():
"""Test Answer node when output variable selector points to non-existent variable"""
graph_config = {
"edges": [
{
"id": "start-source-answer-target",
"source": "start",
"target": "answer",
},
],
"nodes": [
{"data": {"type": "start"}, "id": "start"},
{
"data": {
"title": "Missing variable",
"type": "answer",
"answer": "Test answer",
"outputs": [
{
"variable": "missing_var",
"type": "string",
"value_selector": ["start", "non_existent"]
}
],
},
"id": "answer",
},
],
}
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,
)
# construct variable pool without the referenced variable
variable_pool = VariablePool(
system_variables={SystemVariableKey.FILES: [], SystemVariableKey.USER_ID: "aaa"},
user_inputs={},
environment_variables=[],
conversation_variables=[],
)
node = AnswerNode(
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={
"id": "answer",
"data": {
"title": "Missing variable",
"type": "answer",
"answer": "Test answer",
"outputs": [
{
"variable": "missing_var",
"type": "string",
"value_selector": ["start", "non_existent"]
}
],
},
},
)
# Mock db.session.close()
db.session.close = MagicMock()
# execute node
result = node._run()
assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED
assert result.outputs["answer"] == "Test answer"
# Check that outputs field handles missing variables gracefully
assert "outputs" in result.outputs
outputs = result.outputs["outputs"]
# Missing variables should result in None or empty value
assert outputs.get("missing_var") is None or outputs.get("missing_var") == ""

Loading…
Cancel
Save