feat: 完善工作流 Public API 调用能力
- 支持 JSON 文件 URL 简写与 Multipart 单请求文件上传 - 完善执行拓扑、枚举状态、节点名称、恢复校验和安全错误响应 - 增加临时上传生命周期清理并升级 MinIO SDK - 重构工作流接口调用说明弹窗的扁平响应式布局
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Public API 可安全返回的机器可读错误详情。
|
||||
*/
|
||||
public class PublicApiErrorDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String requestId;
|
||||
private final String location;
|
||||
private final String field;
|
||||
private final String actual;
|
||||
private final List<String> expected;
|
||||
private final boolean retryable;
|
||||
|
||||
/**
|
||||
* 创建公共错误详情。
|
||||
*
|
||||
* @param requestId 请求关联标识
|
||||
* @param location 错误位置
|
||||
* @param field 错误字段
|
||||
* @param actual 经脱敏和限长的实际值
|
||||
* @param expected 合法值或格式
|
||||
* @param retryable 是否适合直接重试
|
||||
*/
|
||||
public PublicApiErrorDetail(
|
||||
String requestId,
|
||||
String location,
|
||||
String field,
|
||||
String actual,
|
||||
List<String> expected,
|
||||
boolean retryable) {
|
||||
this.requestId = requestId;
|
||||
this.location = location;
|
||||
this.field = field;
|
||||
this.actual = actual;
|
||||
this.expected = expected == null
|
||||
? List.of()
|
||||
: List.copyOf(expected);
|
||||
this.retryable = retryable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求关联标识。
|
||||
*
|
||||
* @return 请求关联标识
|
||||
*/
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误位置。
|
||||
*
|
||||
* @return 错误位置
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误字段。
|
||||
*
|
||||
* @return 错误字段
|
||||
*/
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安全实际值。
|
||||
*
|
||||
* @return 实际值
|
||||
*/
|
||||
public String getActual() {
|
||||
return actual;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取期望值。
|
||||
*
|
||||
* @return 不可变期望值列表
|
||||
*/
|
||||
public List<String> getExpected() {
|
||||
return expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否适合直接重试。
|
||||
*
|
||||
* @return 是否可重试
|
||||
*/
|
||||
public boolean isRetryable() {
|
||||
return retryable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流 Public API 执行状态。
|
||||
*
|
||||
* @param executeId 执行 ID
|
||||
* @param status 可读工作流状态
|
||||
* @param terminal 是否已经进入终态
|
||||
* @param message 安全错误消息
|
||||
* @param result 工作流执行结果
|
||||
* @param nodes 节点 ID 到节点状态的映射
|
||||
* @param error 安全错误对象
|
||||
*/
|
||||
public record PublicWorkflowChainStatus(
|
||||
String executeId,
|
||||
PublicWorkflowExecutionStatus status,
|
||||
boolean terminal,
|
||||
String message,
|
||||
Map<String, Object> result,
|
||||
Map<String, PublicWorkflowNodeStatus> nodes,
|
||||
PublicWorkflowStatusError error) implements Serializable {
|
||||
|
||||
/**
|
||||
* 创建不可变公共执行状态。
|
||||
*/
|
||||
public PublicWorkflowChainStatus {
|
||||
nodes = nodes == null
|
||||
? Map.of()
|
||||
: Collections.unmodifiableMap(
|
||||
new LinkedHashMap<>(nodes));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import com.easyagents.flow.core.chain.ChainStatus;
|
||||
import com.easyagents.flow.core.chain.NodeStatus;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
/**
|
||||
* 工作流 Public API 的可读执行状态。
|
||||
*/
|
||||
public enum PublicWorkflowExecutionStatus {
|
||||
|
||||
/** 尚未开始。 */
|
||||
READY("ready", false),
|
||||
/** 正在执行。 */
|
||||
RUNNING("running", false),
|
||||
/** 等待外部参数恢复。 */
|
||||
SUSPENDED("suspended", false),
|
||||
/** 执行发生暂态错误,运行时仍可能继续处理。 */
|
||||
ERROR("error", false),
|
||||
/** 已成功完成。 */
|
||||
DONE("done", true),
|
||||
/** 已失败结束。 */
|
||||
FAILED("failed", true),
|
||||
/** 已取消。 */
|
||||
CANCELLED("cancelled", true),
|
||||
/** 无法识别的状态。 */
|
||||
UNKNOWN("unknown", false);
|
||||
|
||||
/** 对外字符串值。 */
|
||||
private final String value;
|
||||
/** 是否为终态。 */
|
||||
private final boolean terminal;
|
||||
|
||||
/**
|
||||
* 创建公开执行状态。
|
||||
*
|
||||
* @param value 对外字符串值
|
||||
* @param terminal 是否为终态
|
||||
*/
|
||||
PublicWorkflowExecutionStatus(
|
||||
String value,
|
||||
boolean terminal) {
|
||||
this.value = value;
|
||||
this.terminal = terminal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 JSON 响应中的状态值。
|
||||
*
|
||||
* @return 小写状态值
|
||||
*/
|
||||
@JsonValue
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为终态。
|
||||
*
|
||||
* @return 已结束时返回 {@code true}
|
||||
*/
|
||||
public boolean isTerminal() {
|
||||
return terminal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内部工作流状态转换为公开枚举。
|
||||
*
|
||||
* @param status 内部数值状态
|
||||
* @return 公开状态枚举
|
||||
*/
|
||||
public static PublicWorkflowExecutionStatus fromChainStatus(
|
||||
Integer status) {
|
||||
if (status == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
ChainStatus chainStatus = ChainStatus.fromValue(status);
|
||||
if (chainStatus == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
return switch (chainStatus) {
|
||||
case READY -> READY;
|
||||
case RUNNING -> RUNNING;
|
||||
case SUSPEND -> SUSPENDED;
|
||||
case ERROR -> ERROR;
|
||||
case SUCCEEDED -> DONE;
|
||||
case FAILED -> FAILED;
|
||||
case CANCELLED -> CANCELLED;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内部节点状态转换为公开枚举。
|
||||
*
|
||||
* @param status 内部数值状态
|
||||
* @return 公开状态枚举
|
||||
*/
|
||||
public static PublicWorkflowExecutionStatus fromNodeStatus(
|
||||
Integer status) {
|
||||
if (status == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
NodeStatus nodeStatus = NodeStatus.fromValue(status);
|
||||
if (nodeStatus == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
return switch (nodeStatus) {
|
||||
case READY -> READY;
|
||||
case RUNNING -> RUNNING;
|
||||
case SUSPEND -> SUSPENDED;
|
||||
case ERROR -> ERROR;
|
||||
case SUCCEEDED -> DONE;
|
||||
case FAILED -> FAILED;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 工作流 Public API 的安全基础信息。
|
||||
*
|
||||
* @param id 工作流 ID
|
||||
* @param alias 工作流别名
|
||||
* @param title 工作流标题
|
||||
* @param description 工作流描述
|
||||
* @param icon 工作流图标
|
||||
* @param revision 当前发布修订号
|
||||
* @param publishedAt 发布时间,ISO-8601 格式
|
||||
*/
|
||||
public record PublicWorkflowInfo(
|
||||
String id,
|
||||
String alias,
|
||||
String title,
|
||||
String description,
|
||||
String icon,
|
||||
Integer revision,
|
||||
String publishedAt) implements Serializable {
|
||||
|
||||
/**
|
||||
* 从已发布工作流视图创建安全基础信息。
|
||||
*
|
||||
* @param workflow 已发布工作流视图
|
||||
* @return 安全基础信息
|
||||
* @throws IllegalArgumentException 工作流为空时抛出
|
||||
*/
|
||||
public static PublicWorkflowInfo from(Workflow workflow) {
|
||||
if (workflow == null) {
|
||||
throw new IllegalArgumentException("workflow must not be null");
|
||||
}
|
||||
return new PublicWorkflowInfo(
|
||||
workflow.getId() == null
|
||||
? null
|
||||
: workflow.getId().toString(),
|
||||
workflow.getAlias(),
|
||||
workflow.getTitle(),
|
||||
workflow.getDescription(),
|
||||
workflow.getIcon(),
|
||||
workflow.getRevision(),
|
||||
workflow.getPublishedAt() == null
|
||||
? null
|
||||
: workflow.getPublishedAt()
|
||||
.toInstant()
|
||||
.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import com.easyagents.flow.core.chain.Parameter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流 Public API 的节点执行状态。
|
||||
*
|
||||
* @param nodeId 节点 ID
|
||||
* @param nodeName 节点名称
|
||||
* @param status 可读节点状态
|
||||
* @param message 安全错误消息
|
||||
* @param result 节点执行结果
|
||||
* @param suspendForParameters 暂停时等待补充的参数
|
||||
*/
|
||||
public record PublicWorkflowNodeStatus(
|
||||
String nodeId,
|
||||
String nodeName,
|
||||
PublicWorkflowExecutionStatus status,
|
||||
String message,
|
||||
Map<String, Object> result,
|
||||
List<Parameter> suspendForParameters) implements Serializable {
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Public Workflow API JSON 与 Multipart 执行元数据。
|
||||
*/
|
||||
public class PublicWorkflowRunMetadata {
|
||||
|
||||
@NotNull(message = "metadata.id 不能为空")
|
||||
private BigInteger id;
|
||||
private Map<String, Object> variables = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取工作流 ID。
|
||||
*
|
||||
* @return 工作流 ID
|
||||
*/
|
||||
public BigInteger getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置工作流 ID。
|
||||
*
|
||||
* @param id 工作流 ID
|
||||
*/
|
||||
public void setId(BigInteger id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取普通运行变量。
|
||||
*
|
||||
* @return 普通运行变量
|
||||
*/
|
||||
public Map<String, Object> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置普通运行变量。
|
||||
*
|
||||
* @param variables 普通运行变量
|
||||
*/
|
||||
public void setVariables(Map<String, Object> variables) {
|
||||
this.variables = variables == null
|
||||
? new LinkedHashMap<>()
|
||||
: new LinkedHashMap<>(variables);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import tech.easyflow.common.constant.enums.EnumRes;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
|
||||
/**
|
||||
* Public Workflow API 执行响应。
|
||||
*
|
||||
* <p>继承原有 {@link Result} 并继续把执行 ID 放在 {@code data},
|
||||
* 新增 {@code workflow} 区块以保持旧调用方兼容。</p>
|
||||
*/
|
||||
public class PublicWorkflowRunResult extends Result<String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private PublicWorkflowTopology workflow;
|
||||
|
||||
/**
|
||||
* 创建成功响应。
|
||||
*
|
||||
* @param executeId 工作流执行 ID
|
||||
* @param workflow 已发布工作流拓扑
|
||||
* @return 成功响应
|
||||
*/
|
||||
public static PublicWorkflowRunResult success(
|
||||
String executeId,
|
||||
PublicWorkflowTopology workflow) {
|
||||
PublicWorkflowRunResult result = new PublicWorkflowRunResult();
|
||||
result.setErrorCode(EnumRes.SUCCESS.getCode());
|
||||
result.setMessage(EnumRes.SUCCESS.getMsg());
|
||||
result.setData(executeId);
|
||||
result.setWorkflow(workflow);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已发布工作流拓扑。
|
||||
*
|
||||
* @return 工作流拓扑
|
||||
*/
|
||||
public PublicWorkflowTopology getWorkflow() {
|
||||
return workflow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置已发布工作流拓扑。
|
||||
*
|
||||
* @param workflow 工作流拓扑
|
||||
*/
|
||||
public void setWorkflow(PublicWorkflowTopology workflow) {
|
||||
this.workflow = workflow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 工作流公共执行状态中的安全错误信息。
|
||||
*/
|
||||
public class PublicWorkflowStatusError implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String code;
|
||||
private final String message;
|
||||
private final String nodeId;
|
||||
private final String nodeName;
|
||||
private final boolean retryable;
|
||||
|
||||
/**
|
||||
* 创建安全执行错误。
|
||||
*
|
||||
* @param code 稳定错误标识
|
||||
* @param message 安全错误消息
|
||||
* @param nodeId 失败节点 ID
|
||||
* @param nodeName 失败节点名称
|
||||
* @param retryable 当前状态是否仍可能恢复
|
||||
*/
|
||||
public PublicWorkflowStatusError(
|
||||
String code,
|
||||
String message,
|
||||
String nodeId,
|
||||
String nodeName,
|
||||
boolean retryable) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.nodeId = nodeId;
|
||||
this.nodeName = nodeName;
|
||||
this.retryable = retryable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误标识。
|
||||
*
|
||||
* @return 错误标识
|
||||
*/
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安全消息。
|
||||
*
|
||||
* @return 安全消息
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取失败节点 ID。
|
||||
*
|
||||
* @return 节点 ID
|
||||
*/
|
||||
public String getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取失败节点名称。
|
||||
*
|
||||
* @return 节点名称
|
||||
*/
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前状态是否仍可能恢复。
|
||||
*
|
||||
* @return 是否可重试
|
||||
*/
|
||||
public boolean isRetryable() {
|
||||
return retryable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package tech.easyflow.publicapi.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Public Workflow API 对外公开的安全拓扑视图。
|
||||
*
|
||||
* @param workflowId 工作流 ID
|
||||
* @param alias 工作流别名
|
||||
* @param title 工作流标题
|
||||
* @param description 工作流描述
|
||||
* @param revision 发布内容修订号
|
||||
* @param publishedAt 发布时间,ISO-8601 格式
|
||||
* @param nodes 按稳定拓扑顺序排列的节点
|
||||
* @param edges 按发布定义顺序排列的边
|
||||
* @param topologicalOrder 节点 ID 的稳定拓扑顺序
|
||||
* @param topologyLevels 考虑循环体完成屏障后的可并行拓扑层级
|
||||
* @param hasCycle 发布图中是否存在环
|
||||
* @param unresolvedNodeIds 受环路影响而无法进入标准拓扑序的节点 ID
|
||||
*/
|
||||
public record PublicWorkflowTopology(
|
||||
String workflowId,
|
||||
String alias,
|
||||
String title,
|
||||
String description,
|
||||
Integer revision,
|
||||
String publishedAt,
|
||||
List<Node> nodes,
|
||||
List<Edge> edges,
|
||||
List<String> topologicalOrder,
|
||||
List<List<String>> topologyLevels,
|
||||
boolean hasCycle,
|
||||
List<String> unresolvedNodeIds) implements Serializable {
|
||||
|
||||
/**
|
||||
* 创建不可变工作流拓扑。
|
||||
*/
|
||||
public PublicWorkflowTopology {
|
||||
nodes = immutable(nodes);
|
||||
edges = immutable(edges);
|
||||
topologicalOrder = immutable(topologicalOrder);
|
||||
topologyLevels = topologyLevels == null
|
||||
? List.of()
|
||||
: topologyLevels.stream()
|
||||
.map(PublicWorkflowTopology::immutable)
|
||||
.toList();
|
||||
unresolvedNodeIds = immutable(unresolvedNodeIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工作流公开节点。
|
||||
*
|
||||
* @param nodeId 节点 ID
|
||||
* @param nodeType 节点类型
|
||||
* @param nodeName 节点名称
|
||||
* @param description 节点描述
|
||||
* @param parentNodeId 父级容器节点 ID
|
||||
* @param definitionIndex 节点在发布定义中的位置
|
||||
* @param topologyIndex 节点在稳定拓扑序中的位置
|
||||
* @param topologyLevel 节点所在拓扑层级
|
||||
* @param inDegree 发布定义中的原始入度
|
||||
* @param outDegree 发布定义中的原始出度
|
||||
* @param startNode 是否开始节点
|
||||
* @param endNode 是否结束节点
|
||||
* @param predecessorNodeIds 直接前驱节点 ID
|
||||
* @param successorNodeIds 直接后继节点 ID
|
||||
* @param incomingEdgeIds 入边 ID
|
||||
* @param outgoingEdgeIds 出边 ID
|
||||
* @param inputParameters 节点输入参数元数据
|
||||
* @param outputParameters 节点输出参数元数据
|
||||
*/
|
||||
public record Node(
|
||||
String nodeId,
|
||||
String nodeType,
|
||||
String nodeName,
|
||||
String description,
|
||||
String parentNodeId,
|
||||
int definitionIndex,
|
||||
int topologyIndex,
|
||||
int topologyLevel,
|
||||
int inDegree,
|
||||
int outDegree,
|
||||
boolean startNode,
|
||||
boolean endNode,
|
||||
List<String> predecessorNodeIds,
|
||||
List<String> successorNodeIds,
|
||||
List<String> incomingEdgeIds,
|
||||
List<String> outgoingEdgeIds,
|
||||
List<Parameter> inputParameters,
|
||||
List<Parameter> outputParameters) implements Serializable {
|
||||
|
||||
/**
|
||||
* 创建不可变公开节点。
|
||||
*/
|
||||
public Node {
|
||||
predecessorNodeIds = immutable(predecessorNodeIds);
|
||||
successorNodeIds = immutable(successorNodeIds);
|
||||
incomingEdgeIds = immutable(incomingEdgeIds);
|
||||
outgoingEdgeIds = immutable(outgoingEdgeIds);
|
||||
inputParameters = immutable(inputParameters);
|
||||
outputParameters = immutable(outputParameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工作流公开边。
|
||||
*
|
||||
* @param edgeId 边 ID
|
||||
* @param edgeType 边类型
|
||||
* @param label 边展示名称
|
||||
* @param sourceNodeId 源节点 ID
|
||||
* @param targetNodeId 目标节点 ID
|
||||
* @param sourceHandle 源连接点
|
||||
* @param targetHandle 目标连接点
|
||||
* @param parentNodeId 所属父级容器节点 ID
|
||||
* @param definitionIndex 边在发布定义中的位置
|
||||
* @param dangling 是否引用了不存在的节点
|
||||
*/
|
||||
public record Edge(
|
||||
String edgeId,
|
||||
String edgeType,
|
||||
String label,
|
||||
String sourceNodeId,
|
||||
String targetNodeId,
|
||||
String sourceHandle,
|
||||
String targetHandle,
|
||||
String parentNodeId,
|
||||
int definitionIndex,
|
||||
boolean dangling) implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点输入或输出参数的安全元数据。
|
||||
*
|
||||
* @param parameterId 参数 ID
|
||||
* @param name 参数名
|
||||
* @param label 展示名称
|
||||
* @param dataType 数据类型
|
||||
* @param contentType 内容类型
|
||||
* @param required 是否必填
|
||||
* @param description 参数说明
|
||||
* @param multipartPartName 开始节点文件参数对应的 multipart Part 名
|
||||
*/
|
||||
public record Parameter(
|
||||
String parameterId,
|
||||
String name,
|
||||
String label,
|
||||
String dataType,
|
||||
String contentType,
|
||||
boolean required,
|
||||
String description,
|
||||
String multipartPartName) implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将列表转换为不可变副本。
|
||||
*
|
||||
* @param source 原列表
|
||||
* @param <T> 元素类型
|
||||
* @return 不可变列表
|
||||
*/
|
||||
private static <T> List<T> immutable(List<T> source) {
|
||||
return source == null ? List.of() : List.copyOf(source);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user