Skip to content

Commit e135ffc

Browse files
YIXIAO0laipz8200
andauthored
Feat: upgrade variable assigner (langgenius#11285)
Signed-off-by: -LAN- <[email protected]> Co-authored-by: -LAN- <[email protected]>
1 parent e79eac6 commit e135ffc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1564
-300
lines changed

api/controllers/console/app/workflow.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ def post(self, app_model: App):
100100
try:
101101
environment_variables_list = args.get("environment_variables") or []
102102
environment_variables = [
103-
variable_factory.build_variable_from_mapping(obj) for obj in environment_variables_list
103+
variable_factory.build_environment_variable_from_mapping(obj) for obj in environment_variables_list
104104
]
105105
conversation_variables_list = args.get("conversation_variables") or []
106106
conversation_variables = [
107-
variable_factory.build_variable_from_mapping(obj) for obj in conversation_variables_list
107+
variable_factory.build_conversation_variable_from_mapping(obj) for obj in conversation_variables_list
108108
]
109109
workflow = workflow_service.sync_draft_workflow(
110110
app_model=app_model,
@@ -382,7 +382,7 @@ def get(self, app_model: App, block_type: str):
382382
filters = None
383383
if args.get("q"):
384384
try:
385-
filters = json.loads(args.get("q"))
385+
filters = json.loads(args.get("q", ""))
386386
except json.JSONDecodeError:
387387
raise ValueError("Invalid filters")
388388

api/core/app/apps/workflow_app_runner.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
)
4444
from core.workflow.graph_engine.entities.graph import Graph
4545
from core.workflow.nodes import NodeType
46-
from core.workflow.nodes.node_mapping import node_type_classes_mapping
46+
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
4747
from core.workflow.workflow_entry import WorkflowEntry
4848
from extensions.ext_database import db
4949
from models.model import App
@@ -138,7 +138,8 @@ def _get_graph_and_variable_pool_of_single_iteration(
138138

139139
# Get node class
140140
node_type = NodeType(iteration_node_config.get("data", {}).get("type"))
141-
node_cls = node_type_classes_mapping[node_type]
141+
node_version = iteration_node_config.get("data", {}).get("version", "1")
142+
node_cls = NODE_TYPE_CLASSES_MAPPING[node_type][node_version]
142143

143144
# init variable pool
144145
variable_pool = VariablePool(

api/core/variables/types.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33

44
class SegmentType(StrEnum):
5-
NONE = "none"
65
NUMBER = "number"
76
STRING = "string"
7+
OBJECT = "object"
88
SECRET = "secret"
9+
10+
FILE = "file"
11+
912
ARRAY_ANY = "array[any]"
1013
ARRAY_STRING = "array[string]"
1114
ARRAY_NUMBER = "array[number]"
1215
ARRAY_OBJECT = "array[object]"
13-
OBJECT = "object"
14-
FILE = "file"
1516
ARRAY_FILE = "array[file]"
1617

18+
NONE = "none"
19+
1720
GROUP = "group"

api/core/workflow/graph_engine/graph_engine.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from core.workflow.nodes.base import BaseNode
3939
from core.workflow.nodes.end.end_stream_processor import EndStreamProcessor
4040
from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEvent, RunStreamChunkEvent
41-
from core.workflow.nodes.node_mapping import node_type_classes_mapping
41+
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
4242
from extensions.ext_database import db
4343
from models.enums import UserFrom
4444
from models.workflow import WorkflowNodeExecutionStatus, WorkflowType
@@ -227,7 +227,8 @@ def _run(
227227

228228
# convert to specific node
229229
node_type = NodeType(node_config.get("data", {}).get("type"))
230-
node_cls = node_type_classes_mapping[node_type]
230+
node_version = node_config.get("data", {}).get("version", "1")
231+
node_cls = NODE_TYPE_CLASSES_MAPPING[node_type][node_version]
231232

232233
previous_node_id = previous_route_node_state.node_id if previous_route_node_state else None
233234

api/core/workflow/nodes/answer/answer_stream_generate_router.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def _recursive_fetch_answer_dependencies(
153153
NodeType.IF_ELSE,
154154
NodeType.QUESTION_CLASSIFIER,
155155
NodeType.ITERATION,
156-
NodeType.CONVERSATION_VARIABLE_ASSIGNER,
156+
NodeType.VARIABLE_ASSIGNER,
157157
}:
158158
answer_dependencies[answer_node_id].append(source_node_id)
159159
else:

api/core/workflow/nodes/base/entities.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
class BaseNodeData(ABC, BaseModel):
88
title: str
99
desc: Optional[str] = None
10+
version: str = "1"
1011

1112

1213
class BaseIterationNodeData(BaseNodeData):

api/core/workflow/nodes/base/node.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ def __init__(
5555
raise ValueError("Node ID is required.")
5656

5757
self.node_id = node_id
58-
self.node_data: GenericNodeData = cast(GenericNodeData, self._node_data_cls(**config.get("data", {})))
58+
59+
node_data = self._node_data_cls.model_validate(config.get("data", {}))
60+
self.node_data = cast(GenericNodeData, node_data)
5961

6062
@abstractmethod
6163
def _run(self) -> NodeRunResult | Generator[Union[NodeEvent, "InNodeEvent"], None, None]:

api/core/workflow/nodes/enums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ class NodeType(StrEnum):
1414
HTTP_REQUEST = "http-request"
1515
TOOL = "tool"
1616
VARIABLE_AGGREGATOR = "variable-aggregator"
17-
VARIABLE_ASSIGNER = "variable-assigner" # TODO: Merge this into VARIABLE_AGGREGATOR in the database.
17+
LEGACY_VARIABLE_AGGREGATOR = "variable-assigner" # TODO: Merge this into VARIABLE_AGGREGATOR in the database.
1818
LOOP = "loop"
1919
ITERATION = "iteration"
2020
ITERATION_START = "iteration-start" # Fake start node for iteration.
2121
PARAMETER_EXTRACTOR = "parameter-extractor"
22-
CONVERSATION_VARIABLE_ASSIGNER = "assigner"
22+
VARIABLE_ASSIGNER = "assigner"
2323
DOCUMENT_EXTRACTOR = "document-extractor"
2424
LIST_OPERATOR = "list-operator"

api/core/workflow/nodes/iteration/iteration_node.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,13 @@ def _extract_variable_selector_to_variable_mapping(
298298
# variable selector to variable mapping
299299
try:
300300
# Get node class
301-
from core.workflow.nodes.node_mapping import node_type_classes_mapping
301+
from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING
302302

303303
node_type = NodeType(sub_node_config.get("data", {}).get("type"))
304-
node_cls = node_type_classes_mapping.get(node_type)
305-
if not node_cls:
304+
if node_type not in NODE_TYPE_CLASSES_MAPPING:
306305
continue
306+
node_version = sub_node_config.get("data", {}).get("version", "1")
307+
node_cls = NODE_TYPE_CLASSES_MAPPING[node_type][node_version]
307308

308309
sub_node_variable_mapping = node_cls.extract_variable_selector_to_variable_mapping(
309310
graph_config=graph_config, config=sub_node_config
Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections.abc import Mapping
2+
13
from core.workflow.nodes.answer import AnswerNode
24
from core.workflow.nodes.base import BaseNode
35
from core.workflow.nodes.code import CodeNode
@@ -16,26 +18,87 @@
1618
from core.workflow.nodes.template_transform import TemplateTransformNode
1719
from core.workflow.nodes.tool import ToolNode
1820
from core.workflow.nodes.variable_aggregator import VariableAggregatorNode
19-
from core.workflow.nodes.variable_assigner import VariableAssignerNode
21+
from core.workflow.nodes.variable_assigner.v1 import VariableAssignerNode as VariableAssignerNodeV1
22+
from core.workflow.nodes.variable_assigner.v2 import VariableAssignerNode as VariableAssignerNodeV2
23+
24+
LATEST_VERSION = "latest"
2025

21-
node_type_classes_mapping: dict[NodeType, type[BaseNode]] = {
22-
NodeType.START: StartNode,
23-
NodeType.END: EndNode,
24-
NodeType.ANSWER: AnswerNode,
25-
NodeType.LLM: LLMNode,
26-
NodeType.KNOWLEDGE_RETRIEVAL: KnowledgeRetrievalNode,
27-
NodeType.IF_ELSE: IfElseNode,
28-
NodeType.CODE: CodeNode,
29-
NodeType.TEMPLATE_TRANSFORM: TemplateTransformNode,
30-
NodeType.QUESTION_CLASSIFIER: QuestionClassifierNode,
31-
NodeType.HTTP_REQUEST: HttpRequestNode,
32-
NodeType.TOOL: ToolNode,
33-
NodeType.VARIABLE_AGGREGATOR: VariableAggregatorNode,
34-
NodeType.VARIABLE_ASSIGNER: VariableAggregatorNode, # original name of VARIABLE_AGGREGATOR
35-
NodeType.ITERATION: IterationNode,
36-
NodeType.ITERATION_START: IterationStartNode,
37-
NodeType.PARAMETER_EXTRACTOR: ParameterExtractorNode,
38-
NodeType.CONVERSATION_VARIABLE_ASSIGNER: VariableAssignerNode,
39-
NodeType.DOCUMENT_EXTRACTOR: DocumentExtractorNode,
40-
NodeType.LIST_OPERATOR: ListOperatorNode,
26+
NODE_TYPE_CLASSES_MAPPING: Mapping[NodeType, Mapping[str, type[BaseNode]]] = {
27+
NodeType.START: {
28+
LATEST_VERSION: StartNode,
29+
"1": StartNode,
30+
},
31+
NodeType.END: {
32+
LATEST_VERSION: EndNode,
33+
"1": EndNode,
34+
},
35+
NodeType.ANSWER: {
36+
LATEST_VERSION: AnswerNode,
37+
"1": AnswerNode,
38+
},
39+
NodeType.LLM: {
40+
LATEST_VERSION: LLMNode,
41+
"1": LLMNode,
42+
},
43+
NodeType.KNOWLEDGE_RETRIEVAL: {
44+
LATEST_VERSION: KnowledgeRetrievalNode,
45+
"1": KnowledgeRetrievalNode,
46+
},
47+
NodeType.IF_ELSE: {
48+
LATEST_VERSION: IfElseNode,
49+
"1": IfElseNode,
50+
},
51+
NodeType.CODE: {
52+
LATEST_VERSION: CodeNode,
53+
"1": CodeNode,
54+
},
55+
NodeType.TEMPLATE_TRANSFORM: {
56+
LATEST_VERSION: TemplateTransformNode,
57+
"1": TemplateTransformNode,
58+
},
59+
NodeType.QUESTION_CLASSIFIER: {
60+
LATEST_VERSION: QuestionClassifierNode,
61+
"1": QuestionClassifierNode,
62+
},
63+
NodeType.HTTP_REQUEST: {
64+
LATEST_VERSION: HttpRequestNode,
65+
"1": HttpRequestNode,
66+
},
67+
NodeType.TOOL: {
68+
LATEST_VERSION: ToolNode,
69+
"1": ToolNode,
70+
},
71+
NodeType.VARIABLE_AGGREGATOR: {
72+
LATEST_VERSION: VariableAggregatorNode,
73+
"1": VariableAggregatorNode,
74+
},
75+
NodeType.LEGACY_VARIABLE_AGGREGATOR: {
76+
LATEST_VERSION: VariableAggregatorNode,
77+
"1": VariableAggregatorNode,
78+
}, # original name of VARIABLE_AGGREGATOR
79+
NodeType.ITERATION: {
80+
LATEST_VERSION: IterationNode,
81+
"1": IterationNode,
82+
},
83+
NodeType.ITERATION_START: {
84+
LATEST_VERSION: IterationStartNode,
85+
"1": IterationStartNode,
86+
},
87+
NodeType.PARAMETER_EXTRACTOR: {
88+
LATEST_VERSION: ParameterExtractorNode,
89+
"1": ParameterExtractorNode,
90+
},
91+
NodeType.VARIABLE_ASSIGNER: {
92+
LATEST_VERSION: VariableAssignerNodeV2,
93+
"1": VariableAssignerNodeV1,
94+
"2": VariableAssignerNodeV2,
95+
},
96+
NodeType.DOCUMENT_EXTRACTOR: {
97+
LATEST_VERSION: DocumentExtractorNode,
98+
"1": DocumentExtractorNode,
99+
},
100+
NodeType.LIST_OPERATOR: {
101+
LATEST_VERSION: ListOperatorNode,
102+
"1": ListOperatorNode,
103+
},
41104
}

0 commit comments

Comments
 (0)