User select node (#2397)

* feat: add user select node (#2300)

* feat: add user select node

* fix

* type

* fix

* fix

* fix

* perf: user select code

* perf: user select histories

* perf: i18n

---------

Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer
2024-08-15 12:27:04 +08:00
committed by GitHub
parent f8b8fcc172
commit fdeb1590d7
51 changed files with 1060 additions and 184 deletions

View File

@@ -10,7 +10,9 @@ export enum SseResponseEventEnum {
toolParams = 'toolParams', // tool params return
toolResponse = 'toolResponse', // tool response return
flowResponses = 'flowResponses', // sse response request
updateVariables = 'updateVariables'
updateVariables = 'updateVariables',
interactive = 'interactive' // user select
}
export enum DispatchNodeResponseKeyEnum {
@@ -19,7 +21,9 @@ export enum DispatchNodeResponseKeyEnum {
nodeDispatchUsages = 'nodeDispatchUsages', // the node bill.
childrenResponses = 'childrenResponses', // Some nodes make recursive calls that need to be returned
toolResponses = 'toolResponses', // The result is passed back to the tool node for use
assistantResponses = 'assistantResponses' // assistant response
assistantResponses = 'assistantResponses', // assistant response
interactive = 'INTERACTIVE' // is interactive
}
export const needReplaceReferenceInputTypeList = [

View File

@@ -3,7 +3,8 @@ import {
ChatItemType,
UserChatItemValueItemType,
ChatItemValueItemType,
ToolRunResponseItemType
ToolRunResponseItemType,
NodeOutputItemType
} from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { StoreNodeItemType } from '../type/node';
@@ -17,6 +18,7 @@ import { AppDetailType, AppSchema } from '../../app/type';
import { RuntimeNodeItemType } from '../runtime/type';
import { RuntimeEdgeItemType } from './edge';
import { ReadFileNodeResponse } from '../template/system/readFiles/type';
import { UserSelectOptionType } from '../template/system/userSelect/type';
/* workflow props */
export type ChatDispatchProps = {
@@ -153,6 +155,9 @@ export type DispatchNodeResponseType = {
// read files
readFilesResult?: string;
readFiles?: ReadFileNodeResponse;
// user select
userSelectResult?: string;
};
export type DispatchNodeResultType<T> = {

View File

@@ -6,7 +6,9 @@ import { StoreEdgeItemType } from '../type/edge';
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
import { VARIABLE_NODE_ID } from '../constants';
import { isReferenceValue } from '../utils';
import { ReferenceValueProps } from '../type/io';
import { FlowNodeOutputItemType, ReferenceValueProps } from '../type/io';
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
let limit = 10;
@@ -25,7 +27,35 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
return limit * 2;
};
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
const lastAIMessage = histories.findLast((item) => item.obj === ChatRoleEnum.AI);
if (lastAIMessage) {
const interactiveValue = lastAIMessage.value.find(
(v) => v.type === ChatItemValueTypeEnum.interactive
);
if (interactiveValue && 'interactive' in interactiveValue) {
return interactiveValue.interactive;
}
}
return null;
};
export const initWorkflowEdgeStatus = (
edges: StoreEdgeItemType[],
histories?: ChatItemType[]
): RuntimeEdgeItemType[] => {
// If there is a history, use the last interactive value
if (!!histories) {
const memoryEdges = getLastInteractiveValue(histories)?.memoryEdges;
if (memoryEdges && memoryEdges.length > 0) {
return memoryEdges;
}
}
return (
edges?.map((edge) => ({
...edge,
@@ -34,7 +64,19 @@ export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeI
);
};
export const getDefaultEntryNodeIds = (nodes: (StoreNodeItemType | RuntimeNodeItemType)[]) => {
export const getWorkflowEntryNodeIds = (
nodes: (StoreNodeItemType | RuntimeNodeItemType)[],
histories?: ChatItemType[]
) => {
// If there is a history, use the last interactive entry node
if (!!histories) {
const entryNodeIds = getLastInteractiveValue(histories)?.entryNodeIds;
if (Array.isArray(entryNodeIds) && entryNodeIds.length > 0) {
return entryNodeIds;
}
}
const entryList = [
FlowNodeTypeEnum.systemConfig,
FlowNodeTypeEnum.workflowStart,
@@ -212,3 +254,29 @@ export const textAdaptGptResponse = ({
]
});
};
/* Update runtimeNode's outputs with interactive data from history */
export function rewriteNodeOutputByHistories(
histories: ChatItemType[],
runtimeNodes: RuntimeNodeItemType[]
) {
const interactive = getLastInteractiveValue(histories);
if (!interactive?.nodeOutputs) {
return runtimeNodes;
}
return runtimeNodes.map((node) => {
return {
...node,
outputs: node.outputs.map((output: FlowNodeOutputItemType) => {
return {
...output,
value:
interactive?.nodeOutputs?.find(
(item: NodeOutputItemType) => item.nodeId === node.nodeId && item.key === output.key
)?.value || output?.value
};
})
};
});
}