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.node; 017 018import com.agentsflex.core.chain.Chain; 019import com.agentsflex.core.chain.Parameter; 020import com.agentsflex.core.chain.RefType; 021import com.agentsflex.core.chain.node.BaseNode; 022import com.agentsflex.core.util.Maps; 023 024import java.util.*; 025 026public class LoopNode extends BaseNode { 027 028 private Parameter loopVar; 029 private Chain loopChain; 030 031 public Parameter getLoopVar() { 032 return loopVar; 033 } 034 035 public void setLoopVar(Parameter loopVar) { 036 this.loopVar = loopVar; 037 } 038 039 public Chain getLoopChain() { 040 return loopChain; 041 } 042 043 public void setLoopChain(Chain loopChain) { 044 this.loopChain = loopChain; 045 } 046 047 @Override 048 protected Map<String, Object> execute(Chain chain) { 049 loopChain.setParent(chain); 050 Map<String, Object> loopVars = getChainParameters(chain, Collections.singletonList(loopVar)); 051 Maps result = Maps.of(); 052 Object value = loopVars.get(loopVar.getName()); 053 if (value instanceof Iterable) { 054 Iterable<?> iterable = (Iterable<?>) value; 055 int index = 0; 056 for (Object o : iterable) { 057 Map<String, Object> loopParams = new HashMap<>(); 058 loopParams.put("loopItem", o); 059 loopParams.put("index", index++); 060 loopParams.putAll(loopVars); 061 loopParams.putAll(chain.getMemory().getAll()); 062 loopChain.execute(loopParams); 063 fillResult(result, loopChain.getMemory().getAll()); 064 } 065 } else if (value instanceof Number) { 066 int count = ((Number) value).intValue(); 067 for (int i = 0; i < count; i++) { 068 Map<String, Object> loopParams = new HashMap<>(); 069 loopParams.put("loopItem", i); 070 loopParams.put("index", i); 071 loopParams.putAll(loopVars); 072 loopParams.putAll(chain.getMemory().getAll()); 073 loopChain.execute(loopParams); 074 fillResult(result, loopChain.getMemory().getAll()); 075 } 076 } 077 078 List<Parameter> outputDefs = getOutputDefs(); 079 if (outputDefs != null) { 080 for (Parameter outputDef : outputDefs) { 081 if (outputDef.getRefType() == RefType.INPUT) { 082 result.put(outputDef.getName(), outputDef.getRef()); 083 } 084 } 085 } 086 return result; 087 } 088 089 /** 090 * 把子流程执行的结果填充到主流程的输出参数中 091 * 092 * @param result 主流程的输出参数 093 * @param executeResult 子流程的执行结果 094 */ 095 private void fillResult(Maps result, Map<String, Object> executeResult) { 096 List<Parameter> outputDefs = getOutputDefs(); 097 if (outputDefs != null) { 098 for (Parameter outputDef : outputDefs) { 099 if (outputDef.getRefType() == RefType.REF) { 100 Object value = executeResult.get(outputDef.getRef()); 101 @SuppressWarnings("unchecked") List<Object> list = (List<Object>) result.get(outputDef.getName()); 102 if (list == null) list = new ArrayList<>(); 103 list.add(value); 104 result.put(outputDef.getName(), list); 105 } 106 } 107 } 108 } 109}