001/** 002 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.gnu.org/licenses/lgpl-3.0.txt 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package dev.tinyflow.core.parser; 017 018import com.agentsflex.core.chain.Chain; 019import com.agentsflex.core.chain.ChainEdge; 020import com.agentsflex.core.chain.ChainNode; 021import com.agentsflex.core.util.CollectionUtil; 022import com.agentsflex.core.util.StringUtil; 023import com.alibaba.fastjson.JSON; 024import com.alibaba.fastjson.JSONArray; 025import com.alibaba.fastjson.JSONObject; 026import dev.tinyflow.core.Tinyflow; 027import dev.tinyflow.core.parser.impl.*; 028 029import java.util.HashMap; 030import java.util.Map; 031 032public class ChainParser { 033 034 private static final Map<String, NodeParser> nodeParserMap = new HashMap<>(); 035 036 static { 037 nodeParserMap.put("startNode", new StartNodeParser()); 038 nodeParserMap.put("codeNode", new CodeNodeParser()); 039 nodeParserMap.put("templateNode", new TemplateNodeParser()); 040 041 nodeParserMap.put("endNode", new EndNodeParser()); 042 nodeParserMap.put("llmNode", new LlmNodeParser()); 043 } 044 045 public static Chain parse(Tinyflow tinyflow) { 046 String jsonString = tinyflow.getData(); 047 if (StringUtil.noText(jsonString)) { 048 return null; 049 } 050 051 JSONObject root = JSON.parseObject(jsonString); 052 JSONArray nodes = root.getJSONArray("nodes"); 053 JSONArray edges = root.getJSONArray("edges"); 054 055 return parse(tinyflow, nodes, edges, null); 056 } 057 058 public static Chain parse(Tinyflow tinyflow, JSONArray nodes, JSONArray edges, JSONObject parentNode) { 059 if (CollectionUtil.noItems(nodes) || CollectionUtil.noItems(edges)) { 060 return null; 061 } 062 063 Chain chain = new Chain(); 064 for (int i = 0; i < nodes.size(); i++) { 065 JSONObject nodeObject = nodes.getJSONObject(i); 066 if ((parentNode == null && StringUtil.noText(nodeObject.getString("parentId"))) 067 || (parentNode != null && parentNode.getString("id").equals(nodeObject.getString("parentId")))) { 068 ChainNode node = parseNode(tinyflow, nodeObject); 069 if (node != null) { 070 node.setId(nodeObject.getString("id")); 071 chain.addNode(node); 072 } 073 } 074 } 075 076 for (int i = 0; i < edges.size(); i++) { 077 JSONObject edgeObject = edges.getJSONObject(i); 078 JSONObject edgeData = edgeObject.getJSONObject("data"); 079 080 if ((parentNode == null && (edgeData == null || StringUtil.noText(edgeData.getString("parentNodeId")))) 081 || (parentNode != null && edgeData != null && edgeData.getString("parentNodeId").equals(parentNode.getString("id")) 082 //不添加子流程里的第一条 edge(也就是父节点连接子节点的第一条线) 083 && !parentNode.getString("id").equals(edgeObject.getString("source")))) { 084 ChainEdge edge = parseEdge(edgeObject); 085 if (edge != null) { 086 chain.addEdge(edge); 087 } 088 } 089 } 090 091 return chain; 092 } 093 094 private static ChainNode parseNode(Tinyflow tinyflow, JSONObject nodeObject) { 095 String type = nodeObject.getString("type"); 096 if (StringUtil.noText(type)) { 097 return null; 098 } 099 100 NodeParser nodeParser = nodeParserMap.get(type); 101 return nodeParser == null ? null : nodeParser.parse(nodeObject, tinyflow); 102 } 103 104 105 private static ChainEdge parseEdge(JSONObject edgeObject) { 106 if (edgeObject == null) return null; 107 ChainEdge edge = new ChainEdge(); 108 edge.setId(edgeObject.getString("id")); 109 edge.setSource(edgeObject.getString("source")); 110 edge.setTarget(edgeObject.getString("target")); 111 return edge; 112 } 113}