Skip to content

Commit 16a22bc

Browse files
c121914yusd0ric4gggaaallleee
authored
V4.9.5 feature (#4520)
* readme * Add queue log * Test interactive (#4509) * Support nested node interaction (#4503) * feat: Add a new InteractiveContext type and update InteractiveBasicType, adding an optional context property to support more complex interaction state management. * feat: Enhance workflow interactivity by adding InteractiveContext support and updating dispatch logic to manage nested contexts and entry nodes more effectively. * feat: Refactor dispatchWorkFlow to utilize InteractiveContext for improved context management * feat: Enhance entry node resolution by adding validation for entryNodeIds and recursive search in InteractiveContext * feat: Remove workflowDepth from InteractiveContext and update recovery logic to utilize parentContext for improved context management * feat: Update getWorkflowEntryNodeIds to use lastInteractive for improved context handling in runtime nodes * feat: Add lastInteractive support to enhance context management across workflow components * feat: Enhance interactive workflow by adding stopForInteractive flag and improving memory edge validation in runtime logic * feat: Refactor InteractiveContext by removing interactiveAppId and updating runtime edge handling in dispatchRunApp for improved context management * feat: Simplify runtime node and edge initialization in dispatchRunApp by using ternary operators for improved readability and maintainability * feat: Improve memory edge validation in initWorkflowEdgeStatus by adding detailed comments for better understanding of subset checks and recursive context searching * feat: Remove commented-out current level information from InteractiveContext for cleaner code and improved readability * feat: Simplify stopForInteractive check in dispatchWorkFlow for improved code clarity and maintainability * feat: Remove stopForInteractive handling and related references for improved code clarity and maintainability * feat: Add interactive response handling in dispatchRunAppNode for enhanced workflow interactivity * feat: Add context property to InteractiveBasicType and InteractiveNodeType for improved interactivity management * feat: remove comments * feat: Remove the node property from ChatDispatchProps to simplify type definitions * feat: Remove workflowInteractiveResponse from dispatchRunAppNode for cleaner code * feat: Refactor interactive value handling in chat history processing for improved clarity * feat: Simplify initWorkflowEdgeStatus logic for better readability and maintainability * feat: Add workflowInteractiveResponse to dispatchWorkFlow for enhanced functionality * feat: Enhance interactive response handling with nested children support * feat: Remove commented-out code for interactive node handling to improve clarity * feat: remove InteractiveContext type * feat: Refactor UserSelectInteractive and UserInputInteractive params for improved structure and clarity * feat: remove * feat: The front end supports extracting the deepest interaction parameters to enhance interaction processing * feat: The front end supports extracting the deepest interaction parameters to enhance interaction processing * fix: handle undefined interactive values in runtimeEdges and runtimeNodes initialization * fix: handle undefined interactive values in runtimeNodes and runtimeEdges initialization * fix: update runtimeNodes and runtimeEdges initialization to use last interactive value * fix: remove unused imports and replace getLastInteractiveValue with lastInteractive in runtimeEdges initialization * fix: import WorkflowInteractiveResponseType and handle lastInteractive as undefined in chatTest * feat: implement extractDeepestInteractive function and refactor usage in AIResponseBox and ChatBox utils * fix: refactor initWorkflowEdgeStatus and getWorkflowEntryNodeIds calls in dispatchRunAppNode for recovery handling * fix: ensure lastInteractive is handled consistently as undefined in runtimeEdges and runtimeNodes initialization * fix: update dispatchFormInput and dispatchUserSelect to use lastInteractive consistently * fix: update condition checks in dispatchFormInput and dispatchUserSelect to ensure lastInteractive type is validated correctly * fix: refactor dispatchRunAppNode to replace isRecovery with childrenInteractive for improved clarity in runtimeNodes and runtimeEdges initialization * refactor: streamline runtimeNodes and runtimeEdges initialization in dispatchRunAppNode for improved readability and maintainability * fix: update rewriteNodeOutputByHistories function to accept runtimeNodes and interactive as parameters for improved clarity * fix: simplify interactiveResponse assignment in dispatchWorkFlow for improved clarity * fix: update entryNodeIds check in getWorkflowEntryNodeIds to ensure it's an array for improved reliability * remove some invalid code --------- Co-authored-by: Theresa <[email protected]> * update doc * update log * fix: update debug workflow to conditionally include nextStepSkipNodes… (#4511) * fix: update debug workflow to conditionally include nextStepSkipNodes based on lastInteractive for improved debugging accuracy * fix : type error * remove invalid code * fix: QA queue * fix: interactive * Test log (#4519) * add log (#4504) * add log * update log i18n * update log * delete template * add i18NT * add team operation log --------- Co-authored-by: gggaaallleee <[email protected]> * remove search * update doc --------- Co-authored-by: Theresa <[email protected]> Co-authored-by: gggaaallleee <[email protected]>
1 parent b51a87f commit 16a22bc

File tree

34 files changed

+663
-205
lines changed

34 files changed

+663
-205
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<a href="./README_ja.md">日语</a>
1111
</p>
1212

13-
FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景
13+
FastGPT 是一个 AI Agent 构建平台,提供开箱即用的数据处理、模型调用等能力同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的应用场景
1414

1515
</div>
1616

docSite/content/zh-cn/docs/development/upgrading/495.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@ weight: 795
1111
## 🚀 新增内容
1212

1313
1. 团队成员权限细分,可分别控制是否可创建在根目录应用/知识库以及 API Key
14+
2. 支持交互节点在嵌套工作流中使用。
15+
3. 团队成员操作日志。
1416

1517
## ⚙️ 优化
1618

19+
1. 繁体中文翻译。
20+
1721

1822
## 🐛 修复
1923

20-
1. password 检测规则错误
24+
1. password 检测规则错误。
25+
2. 分享链接无法隐藏知识库检索结果。
26+
3. IOS 低版本正则兼容问题。
27+
4. 修复问答提取队列错误后,计数器未清零问题,导致问答提取队列失效。
28+
5. Debug 模式交互节点下一步可能造成死循环。

packages/global/core/workflow/runtime/type.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { WorkflowResponseType } from '../../../../service/core/workflow/dispatch
2323
import { AiChatQuoteRoleType } from '../template/system/aiChat/type';
2424
import { LafAccountType, OpenaiAccountType } from '../../../support/user/team/type';
2525
import { CompletionFinishReason } from '../../ai/type';
26-
26+
import { WorkflowInteractiveResponseType } from '../template/system/interactive/type';
2727
export type ExternalProviderType = {
2828
openaiAccount?: OpenaiAccountType;
2929
externalWorkflowVariables?: Record<string, string>;
@@ -55,6 +55,7 @@ export type ChatDispatchProps = {
5555
variables: Record<string, any>; // global variable
5656
query: UserChatItemValueItemType[]; // trigger query
5757
chatConfig: AppSchema['chatConfig'];
58+
lastInteractive?: WorkflowInteractiveResponseType; // last interactive response
5859
stream: boolean;
5960
maxRunTimes: number;
6061
isToolCall?: boolean;

packages/global/core/workflow/runtime/utils.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,19 @@ import { FlowNodeOutputItemType, ReferenceValueType } from '../type/io';
1010
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
1111
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
1212
import { replaceVariable, valToStr } from '../../../common/string/tools';
13-
13+
import {
14+
InteractiveNodeResponseType,
15+
WorkflowInteractiveResponseType
16+
} from '../template/system/interactive/type';
17+
18+
export const extractDeepestInteractive = (
19+
interactive: WorkflowInteractiveResponseType
20+
): WorkflowInteractiveResponseType => {
21+
if (interactive?.type === 'childrenInteractive' && interactive.params?.childrenResponse) {
22+
return extractDeepestInteractive(interactive.params.childrenResponse);
23+
}
24+
return interactive;
25+
};
1426
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
1527
let limit = 10;
1628
nodes.forEach((node) => {
@@ -34,7 +46,9 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
3446
1. Get the interactive data
3547
2. Check that the workflow starts at the interaction node
3648
*/
37-
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
49+
export const getLastInteractiveValue = (
50+
histories: ChatItemType[]
51+
): WorkflowInteractiveResponseType | undefined => {
3852
const lastAIMessage = [...histories].reverse().find((item) => item.obj === ChatRoleEnum.AI);
3953

4054
if (lastAIMessage) {
@@ -45,7 +59,11 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
4559
lastValue.type !== ChatItemValueTypeEnum.interactive ||
4660
!lastValue.interactive
4761
) {
48-
return null;
62+
return;
63+
}
64+
65+
if (lastValue.interactive.type === 'childrenInteractive') {
66+
return lastValue.interactive;
4967
}
5068

5169
// Check is user select
@@ -62,38 +80,29 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
6280
}
6381
}
6482

65-
return null;
83+
return;
6684
};
6785

6886
export const initWorkflowEdgeStatus = (
69-
edges: StoreEdgeItemType[] | RuntimeEdgeItemType[],
70-
histories?: ChatItemType[]
87+
edges: StoreEdgeItemType[],
88+
lastInteractive?: WorkflowInteractiveResponseType
7189
): RuntimeEdgeItemType[] => {
72-
// If there is a history, use the last interactive value
73-
if (histories && histories.length > 0) {
74-
const memoryEdges = getLastInteractiveValue(histories)?.memoryEdges;
75-
90+
if (lastInteractive) {
91+
const memoryEdges = lastInteractive.memoryEdges || [];
7692
if (memoryEdges && memoryEdges.length > 0) {
7793
return memoryEdges;
7894
}
7995
}
8096

81-
return (
82-
edges?.map((edge) => ({
83-
...edge,
84-
status: 'waiting'
85-
})) || []
86-
);
97+
return edges?.map((edge) => ({ ...edge, status: 'waiting' })) || [];
8798
};
8899

89100
export const getWorkflowEntryNodeIds = (
90101
nodes: (StoreNodeItemType | RuntimeNodeItemType)[],
91-
histories?: ChatItemType[]
102+
lastInteractive?: WorkflowInteractiveResponseType
92103
) => {
93-
// If there is a history, use the last interactive entry node
94-
if (histories && histories.length > 0) {
95-
const entryNodeIds = getLastInteractiveValue(histories)?.entryNodeIds;
96-
104+
if (lastInteractive) {
105+
const entryNodeIds = lastInteractive.entryNodeIds || [];
97106
if (Array.isArray(entryNodeIds) && entryNodeIds.length > 0) {
98107
return entryNodeIds;
99108
}
@@ -396,10 +405,10 @@ export const textAdaptGptResponse = ({
396405

397406
/* Update runtimeNode's outputs with interactive data from history */
398407
export function rewriteNodeOutputByHistories(
399-
histories: ChatItemType[],
400-
runtimeNodes: RuntimeNodeItemType[]
408+
runtimeNodes: RuntimeNodeItemType[],
409+
lastInteractive?: InteractiveNodeResponseType
401410
) {
402-
const interactive = getLastInteractiveValue(histories);
411+
const interactive = lastInteractive;
403412
if (!interactive?.nodeOutputs) {
404413
return runtimeNodes;
405414
}

packages/global/core/workflow/template/system/interactive/type.d.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { NodeOutputItemType } from '../../../../chat/type';
22
import type { FlowNodeOutputItemType } from '../../../type/io';
3-
import type { RuntimeEdgeItemType } from '../../../runtime/type';
43
import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
54
import { WorkflowIOValueTypeEnum } from 'core/workflow/constants';
65
import type { ChatCompletionMessageParam } from '../../../../ai/type';
@@ -9,7 +8,6 @@ type InteractiveBasicType = {
98
entryNodeIds: string[];
109
memoryEdges: RuntimeEdgeItemType[];
1110
nodeOutputs: NodeOutputItemType[];
12-
1311
toolParams?: {
1412
entryNodeIds: string[]; // 记录工具中,交互节点的 Id,而不是起始工作流的入口
1513
memoryMessages: ChatCompletionMessageParam[]; // 这轮工具中,产生的新的 messages
@@ -23,6 +21,13 @@ type InteractiveNodeType = {
2321
nodeOutputs?: NodeOutputItemType[];
2422
};
2523

24+
type ChildrenInteractive = InteractiveNodeType & {
25+
type: 'childrenInteractive';
26+
params: {
27+
childrenResponse?: WorkflowInteractiveResponseType;
28+
};
29+
};
30+
2631
export type UserSelectOptionItemType = {
2732
key: string;
2833
value: string;
@@ -62,5 +67,9 @@ type UserInputInteractive = InteractiveNodeType & {
6267
submitted?: boolean;
6368
};
6469
};
65-
export type InteractiveNodeResponseType = UserSelectInteractive | UserInputInteractive;
70+
71+
export type InteractiveNodeResponseType =
72+
| UserSelectInteractive
73+
| UserInputInteractive
74+
| ChildrenInteractive;
6675
export type WorkflowInteractiveResponseType = InteractiveBasicType & InteractiveNodeResponseType;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export enum OperationLogEventEnum {
2+
LOGIN = 'LOGIN',
3+
CREATE_INVITATION_LINK = 'CREATE_INVITATION_LINK',
4+
JOIN_TEAM = 'JOIN_TEAM',
5+
CHANGE_MEMBER_NAME = 'CHANGE_MEMBER_NAME',
6+
KICK_OUT_TEAM = 'KICK_OUT_TEAM',
7+
CREATE_DEPARTMENT = 'CREATE_DEPARTMENT',
8+
CHANGE_DEPARTMENT = 'CHANGE_DEPARTMENT',
9+
DELETE_DEPARTMENT = 'DELETE_DEPARTMENT',
10+
RELOCATE_DEPARTMENT = 'RELOCATE_DEPARTMENT',
11+
CREATE_GROUP = 'CREATE_GROUP',
12+
DELETE_GROUP = 'DELETE_GROUP',
13+
ASSIGN_PERMISSION = 'ASSIGN_PERMISSION'
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { SourceMemberType } from '../user/type';
2+
import { OperationLogEventEnum } from './constants';
3+
4+
export type OperationLogSchema = {
5+
_id: string;
6+
tmbId: string;
7+
teamId: string;
8+
timestamp: Date;
9+
event: `${OperationLogEventEnum}`;
10+
metadata?: Record<string, string>;
11+
};
12+
13+
export type OperationListItemType = {
14+
_id: string;
15+
sourceMember: SourceMemberType;
16+
event: `${OperationLogEventEnum}`;
17+
timestamp: Date;
18+
metadata: Record<string, string>;
19+
};

packages/global/support/permission/user/controller.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { PerConstructPros, Permission } from '../controller';
22
import {
3+
TeamApikeyCreatePermissionVal,
34
TeamAppCreatePermissionVal,
5+
TeamDatasetCreatePermissionVal,
46
TeamDefaultPermissionVal,
57
TeamPermissionList
68
} from './constant';
@@ -23,8 +25,8 @@ export class TeamPermission extends Permission {
2325

2426
this.setUpdatePermissionCallback(() => {
2527
this.hasAppCreatePer = this.checkPer(TeamAppCreatePermissionVal);
26-
this.hasDatasetCreatePer = this.checkPer(TeamAppCreatePermissionVal);
27-
this.hasApikeyCreatePer = this.checkPer(TeamAppCreatePermissionVal);
28+
this.hasDatasetCreatePer = this.checkPer(TeamDatasetCreatePermissionVal);
29+
this.hasApikeyCreatePer = this.checkPer(TeamApikeyCreatePermissionVal);
2830
});
2931
}
3032
}

packages/service/core/chat/saveChat.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
1616
import { pushChatLog } from './pushChatLog';
1717
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
1818
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
19+
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
1920

2021
type Props = {
2122
chatId: string;
@@ -209,34 +210,24 @@ export const updateInteractiveChat = async ({
209210
}
210211
})();
211212

212-
if (interactiveValue.interactive.type === 'userSelect') {
213-
interactiveValue.interactive = {
214-
...interactiveValue.interactive,
215-
params: {
216-
...interactiveValue.interactive.params,
217-
userSelectedVal: userInteractiveVal
218-
}
219-
};
213+
let finalInteractive = extractDeepestInteractive(interactiveValue.interactive);
214+
215+
if (finalInteractive.type === 'userSelect') {
216+
finalInteractive.params.userSelectedVal = userInteractiveVal;
220217
} else if (
221-
interactiveValue.interactive.type === 'userInput' &&
218+
finalInteractive.type === 'userInput' &&
222219
typeof parsedUserInteractiveVal === 'object'
223220
) {
224-
interactiveValue.interactive = {
225-
...interactiveValue.interactive,
226-
params: {
227-
...interactiveValue.interactive.params,
228-
inputForm: interactiveValue.interactive.params.inputForm.map((item) => {
229-
const itemValue = parsedUserInteractiveVal[item.label];
230-
return itemValue !== undefined
231-
? {
232-
...item,
233-
value: itemValue
234-
}
235-
: item;
236-
}),
237-
submitted: true
238-
}
239-
};
221+
finalInteractive.params.inputForm = finalInteractive.params.inputForm.map((item) => {
222+
const itemValue = parsedUserInteractiveVal[item.label];
223+
return itemValue !== undefined
224+
? {
225+
...item,
226+
value: itemValue
227+
}
228+
: item;
229+
});
230+
finalInteractive.params.submitted = true;
240231
}
241232

242233
if (aiResponse.customFeedbacks) {

0 commit comments

Comments
 (0)