diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/listener/ChatStreamListener.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/listener/ChatStreamListener.java index edb61fc..e5f838e 100644 --- a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/listener/ChatStreamListener.java +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/listener/ChatStreamListener.java @@ -8,7 +8,6 @@ import com.easyagents.core.model.chat.StreamResponseListener; import com.easyagents.core.model.chat.response.AiMessageResponse; import com.easyagents.core.model.client.StreamContext; import com.easyagents.core.prompt.MemoryPrompt; -import org.apache.catalina.connector.ClientAbortException; import tech.easyflow.core.chat.protocol.ChatDomain; import tech.easyflow.core.chat.protocol.ChatEnvelope; import tech.easyflow.core.chat.protocol.ChatType; @@ -20,6 +19,7 @@ import java.io.IOException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; public class ChatStreamListener implements StreamResponseListener { @@ -32,6 +32,8 @@ public class ChatStreamListener implements StreamResponseListener { private boolean canStop = true; // 辅助标记:是否进入过工具调用(避免重复递归判断) private boolean hasToolCall = false; + // 流式响应只能结束一次,避免重复发送导致 IllegalStateException + private final AtomicBoolean completed = new AtomicBoolean(false); public ChatStreamListener(String conversationId, ChatModel chatModel, MemoryPrompt memoryPrompt, ChatSseEmitter sseEmitter, ChatOptions chatOptions) { this.conversationId = conversationId; @@ -86,7 +88,7 @@ public class ChatStreamListener implements StreamResponseListener { @Override public void onStop(StreamContext context) { // 仅当canStop为true(最后一次无后续工具调用的响应)时,执行业务逻辑 - if (this.canStop) { + if (this.canStop && completed.compareAndSet(false, true)) { System.out.println("onStop"); if (context.getThrowable() != null) { sendSystemError(sseEmitter, context.getThrowable().getMessage()); @@ -103,7 +105,7 @@ public class ChatStreamListener implements StreamResponseListener { @Override public void onFailure(StreamContext context, Throwable throwable) { - if (throwable != null) { + if (throwable != null && completed.compareAndSet(false, true)) { throwable.printStackTrace(); sendSystemError(sseEmitter, throwable.getMessage()); } diff --git a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/tool/WorkflowTool.java b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/tool/WorkflowTool.java index 777db7a..8076aa6 100644 --- a/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/tool/WorkflowTool.java +++ b/easyflow-modules/easyflow-module-ai/src/main/java/tech/easyflow/ai/easyagents/tool/WorkflowTool.java @@ -9,9 +9,7 @@ import tech.easyflow.ai.entity.Workflow; import tech.easyflow.common.util.SpringContextUtil; import java.math.BigInteger; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; public class WorkflowTool extends BaseTool { @@ -43,18 +41,88 @@ public class WorkflowTool extends BaseTool { Parameter[] parameters = new Parameter[parameterDefs.size()]; for (int i = 0; i < parameterDefs.size(); i++) { com.easyagents.flow.core.chain.Parameter parameterDef = parameterDefs.get(i); - Parameter parameter = new Parameter(); - parameter.setName(parameterDef.getName()); - parameter.setDescription(parameterDef.getDescription()); - DataType dataType = parameterDef.getDataType(); - if (dataType == null) dataType = DataType.String; - parameter.setType(dataType.toString()); - parameter.setRequired(parameterDef.isRequired()); - parameters[i] = parameter; + parameters[i] = toToolParameter(parameterDef); } return parameters; } + private static Parameter toToolParameter(com.easyagents.flow.core.chain.Parameter parameterDef) { + Parameter parameter = new Parameter(); + parameter.setName(parameterDef.getName()); + parameter.setDescription(parameterDef.getDescription()); + parameter.setRequired(parameterDef.isRequired()); + + DataType dataType = parameterDef.getDataType(); + if (dataType == null) { + dataType = DataType.String; + } + + switch (dataType) { + case Object: + parameter.setType("object"); + parameter.setChildren(toToolChildren(parameterDef.getChildren())); + break; + case Array: + parameter.setType("array"); + parameter.setChildren(toToolChildren(parameterDef.getChildren())); + break; + case Array_Object: + parameter.setType("array"); + parameter.setChildren(Collections.singletonList(buildArrayItem("object", parameterDef.getChildren()))); + break; + case Array_String: + parameter.setType("array"); + parameter.setChildren(Collections.singletonList(buildArrayItem("string", null))); + break; + case Array_Number: + parameter.setType("array"); + parameter.setChildren(Collections.singletonList(buildArrayItem("number", null))); + break; + case Array_Boolean: + parameter.setType("array"); + parameter.setChildren(Collections.singletonList(buildArrayItem("boolean", null))); + break; + case Array_File: + parameter.setType("array"); + parameter.setChildren(Collections.singletonList(buildArrayItem("string", null))); + break; + case Number: + parameter.setType("number"); + break; + case Boolean: + parameter.setType("boolean"); + break; + case File: + parameter.setType("string"); + break; + case String: + default: + parameter.setType("string"); + break; + } + + return parameter; + } + + private static List toToolChildren(List parameterDefs) { + if (parameterDefs == null || parameterDefs.isEmpty()) { + return null; + } + List children = new ArrayList<>(parameterDefs.size()); + for (com.easyagents.flow.core.chain.Parameter childDef : parameterDefs) { + children.add(toToolParameter(childDef)); + } + return children; + } + + private static Parameter buildArrayItem(String itemType, List childrenDefs) { + Parameter item = new Parameter(); + item.setName(null); + item.setType(itemType); + item.setChildren(toToolChildren(childrenDefs)); + return item; + } + public BigInteger getWorkflowId() { return workflowId; }