V4.13.2 features (#5792)

* add manual create http toolset (#5743)

* add manual create http toolset

* optimize code

* optimize

* fix

* fix

* rename filename

* feat: integrate ts-rest (#5741)

* feat: integrate ts-rest

* chore: classify core contract and pro contract

* chore: update lockfile

* chore: tweak dir structure

* chore: tweak dir structure

* update tsrest code (#5755)

* doc

* update tsrest code

* fix http toolset (#5753)

* fix http toolset

* fix

* perf: http toolset

* fix: toolresponse result (#5760)

* doc

* fix: toolresponse result

* fix: mongo watch

* remove log

* feat: integrated to minio (#5748)

* feat: migrate to minio

* feat: migrate apps' and dataset's avatar to minio

* feat: migrate more avatars to minio

* fix: lock file

* feat: migrate copyright settings' logo to minio

* feat: integrate minio

* chore: improve code

* chore: rename variables

* refactor: s3 class

* fix: s3 and mongo operations

* chore: add session for avatar source

* fix: init s3 buckets

* fix: bugbot issues

* expired time code

* perf: avatar code

* union type

* export favouriteContract

* empty bucket check

---------

Co-authored-by: archer <545436317@qq.com>

* refactor: zod schema to generate OpenAPI instead (#5771)

* doc

* fix: text split code (#5773)

* fix: toolresponse result

* remove log

* stream remove

* fix: text split code

* fix: workflow (#5779)

* fix: toolresponse result

* remove log

* fix: value check

* fix: workflow

* openapi doc

* perf: bucket delete cron

* doc

* feat: apikey health

* feat: export variables

* api code move

* perf: workflow performance (#5783)

* perf: reactflow context

* perf: workflow context split

* perf: nodeList computed map

* perf: nodes dependen

* perf: workflow performance

* workflow performance

* removel og

* lock

* version

* loop drag

* reactflow size

* reactflow size

* fix: s3init (#5784)

* doc

* fix: s3init

* perf: dynamic import

* remove moongose dep

* worker build

* worker code

* perf: worker build

* fix: error throw

* doc

* doc

* fix: build

* fix: dockerfile

* nextjs config

* fix: worker

* fix: build (#5791)

* fix: build

* vector cache code

* fix: app info modal avatar upload method replace (#5787)

* fix: app info modal avatar upload method replace

* chore: replace all useSelectFile with useUploadAvatar

* remove invalid code

* add size

* Update projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/CommonInputForm.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update projects/app/src/pageComponents/app/detail/WorkflowComponents/context/workflowInitContext.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Archer
2025-10-20 19:08:21 +08:00
committed by GitHub
parent ca3053f04d
commit 44e9299d5e
253 changed files with 18343 additions and 9623 deletions
+27 -63
View File
@@ -21,17 +21,6 @@ import { isValidReferenceValueFormat } from '../utils';
import type { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
import { isSecretValue } from '../../../common/secret/utils';
export const checkIsBranchNode = (node: RuntimeNodeItemType) => {
if (node.catchError) return true;
const map: Record<any, boolean> = {
[FlowNodeTypeEnum.classifyQuestion]: true,
[FlowNodeTypeEnum.userSelect]: true,
[FlowNodeTypeEnum.ifElseNode]: true
};
return !!map[node.flowNodeType];
};
export const extractDeepestInteractive = (
interactive: WorkflowInteractiveResponseType
): WorkflowInteractiveResponseType => {
@@ -306,45 +295,50 @@ export const checkNodeRunStatus = ({
}) => {
const filterRuntimeEdges = filterWorkflowEdges(runtimeEdges);
const isStartNode = (nodeType: string) => {
const map: Record<any, boolean> = {
[FlowNodeTypeEnum.workflowStart]: true,
[FlowNodeTypeEnum.pluginInput]: true
};
return !!map[nodeType];
};
const splitNodeEdges = (targetNode: RuntimeNodeItemType) => {
const commonEdges: RuntimeEdgeItemType[] = [];
const recursiveEdgeGroupsMap = new Map<string, RuntimeEdgeItemType[]>();
const getEdgeLastBranchHandle = ({
startEdge,
targetNodeId
}: {
startEdge: RuntimeEdgeItemType;
targetNodeId: string;
}): string | '' | undefined => {
const sourceEdges = filterRuntimeEdges.filter((item) => item.target === targetNode.nodeId);
sourceEdges.forEach((sourceEdge) => {
const stack: Array<{
edge: RuntimeEdgeItemType;
visited: Set<string>;
lasestBranchHandle?: string;
}> = [
{
edge: startEdge,
visited: new Set([targetNodeId])
edge: sourceEdge,
visited: new Set([targetNode.nodeId])
}
];
const MAX_DEPTH = 3000;
let iterations = 0;
while (stack.length > 0 && iterations < MAX_DEPTH) {
iterations++;
const { edge, visited, lasestBranchHandle } = stack.pop()!;
const { edge, visited } = stack.pop()!;
// Circle
// Start node
const sourceNode = nodesMap.get(edge.source);
if (!sourceNode) continue;
if (isStartNode(sourceNode.flowNodeType)) {
commonEdges.push(sourceEdge);
continue;
}
// Circle detected
if (edge.source === targetNode.nodeId) {
// 检查自身是否为分支节点
const node = nodesMap.get(edge.source);
if (!node) return '';
const isBranch = checkIsBranchNode(node);
if (isBranch) return edge.sourceHandle;
// 检测到环,并且环中包含当前节点. 空字符代表是一个无分支循环,属于死循环,则忽略这个边。
return lasestBranchHandle ?? '';
recursiveEdgeGroupsMap.set(edge.target, [
...(recursiveEdgeGroupsMap.get(edge.target) || []),
sourceEdge
]);
continue;
}
if (visited.has(edge.source)) {
@@ -357,42 +351,12 @@ export const checkNodeRunStatus = ({
// 查找目标节点的 source edges 并加入栈中
const nextEdges = filterRuntimeEdges.filter((item) => item.target === edge.source);
for (const nextEdge of nextEdges) {
const node = nodesMap.get(nextEdge.target);
if (!node) continue;
const isBranch = checkIsBranchNode(node);
stack.push({
edge: nextEdge,
visited: newVisited,
lasestBranchHandle: isBranch ? edge.sourceHandle : lasestBranchHandle
visited: newVisited
});
}
}
return;
};
const sourceEdges = filterRuntimeEdges.filter((item) => item.target === targetNode.nodeId);
sourceEdges.forEach((edge) => {
const lastBranchHandle = getEdgeLastBranchHandle({
startEdge: edge,
targetNodeId: targetNode.nodeId
});
// 无效的循环,这条边则忽略
if (lastBranchHandle === '') return;
// 有效循环,则加入递归组
if (lastBranchHandle) {
recursiveEdgeGroupsMap.set(lastBranchHandle, [
...(recursiveEdgeGroupsMap.get(lastBranchHandle) || []),
edge
]);
}
// 无循环的连线,则加入普通组
else {
commonEdges.push(edge);
}
});
return { commonEdges, recursiveEdgeGroups: Array.from(recursiveEdgeGroupsMap.values()) };