Perf input guide (#1557)

* perf: input guide code

* perf: input guide ui

* Chat input guide api

* Update app chat config store

* perf: app chat config field

* perf: app context

* perf: params

* fix: ts

* perf: filter private config

* perf: filter private config

* perf: import workflow

* perf: limit max tip amount
This commit is contained in:
Archer
2024-05-21 17:52:04 +08:00
committed by GitHub
parent 8e8ceb7439
commit fb368a581c
123 changed files with 2124 additions and 1805 deletions

View File

@@ -6,7 +6,7 @@ import { MongoApp } from '@fastgpt/service/core/app/schema';
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { NextAPI } from '@/service/middleware/entry';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {

View File

@@ -5,9 +5,9 @@ import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { MongoAppQGuide } from '@fastgpt/service/core/app/qGuideSchema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { NextAPI } from '@/service/middleware/entry';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
@@ -47,7 +47,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
},
{ session }
);
await MongoAppQGuide.deleteMany(
await MongoChatInputGuide.deleteMany(
{
appId
},

View File

@@ -1,6 +1,4 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { NextAPI } from '@/service/middleware/entry';

View File

@@ -1,20 +1,20 @@
import { authUserNotVisitor } from '@fastgpt/service/support/permission/auth/user';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoAppQGuide } from '@fastgpt/service/core/app/qGuideSchema';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import axios from 'axios';
import { NextAPI } from '@/service/middleware/entry';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { textList = [], appId, customURL } = req.body;
const { textList = [], appId, customUrl } = req.body;
if (!customURL) {
if (!customUrl) {
const { teamId } = await authUserNotVisitor({ req, authToken: true });
const currentQGuide = await MongoAppQGuide.find({ appId, teamId });
const currentQGuide = await MongoChatInputGuide.find({ appId, teamId });
const currentTexts = currentQGuide.map((item) => item.text);
const textsToDelete = currentTexts.filter((text) => !textList.includes(text));
await MongoAppQGuide.deleteMany({ text: { $in: textsToDelete }, appId, teamId });
await MongoChatInputGuide.deleteMany({ text: { $in: textsToDelete }, appId, teamId });
const newTexts = textList.filter((text: string) => !currentTexts.includes(text));
@@ -24,10 +24,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
teamId: teamId
}));
await MongoAppQGuide.insertMany(newDocuments);
await MongoChatInputGuide.insertMany(newDocuments);
} else {
try {
const response = await axios.post(customURL, {
const response = await axios.post(customUrl, {
textList,
appId
});

View File

@@ -1,48 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { MongoAppQGuide } from '@fastgpt/service/core/app/qGuideSchema';
import axios from 'axios';
import { PaginationProps } from '@fastgpt/web/common/fetch/type';
import { NextAPI } from '@/service/middleware/entry';
type Props = PaginationProps<{
appId: string;
customURL: string;
searchKey: string;
}>;
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId, customURL, current, pageSize, searchKey } = req.query as unknown as Props;
if (!customURL) {
const [result, total] = await Promise.all([
MongoAppQGuide.find({
appId,
...(searchKey && { text: { $regex: new RegExp(searchKey, 'i') } })
})
.sort({
time: -1
})
.skip((current - 1) * pageSize)
.limit(pageSize),
MongoAppQGuide.countDocuments({ appId })
]);
return {
list: result.map((item) => item.text) || [],
total
};
} else {
try {
const response = await axios.get(customURL as string, {
params: {
appid: appId
}
});
res.status(200).json(response.data);
} catch (error) {
res.status(500).json({ error });
}
}
}
export default NextAPI(handler);

View File

@@ -7,7 +7,7 @@ import { NextAPI } from '@/service/middleware/entry';
/* 获取我的模型 */
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { name, avatar, type, intro, nodes, edges, permission, teamTags } =
const { name, avatar, type, intro, nodes, edges, chatConfig, permission, teamTags } =
req.body as AppUpdateParams;
const { appId } = req.query as { appId: string };
@@ -39,7 +39,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
}),
...(edges && {
edges
})
}),
...(chatConfig && { chatConfig })
}
);
}

View File

@@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';

View File

@@ -1,11 +1,10 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { PostPublishAppProps } from '@/global/core/app/api';
@@ -13,14 +12,12 @@ type Response = {};
async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<{}> {
const { appId } = req.query as { appId: string };
const { nodes = [], edges = [], type } = req.body as PostPublishAppProps;
const { nodes = [], edges = [], chatConfig, type } = req.body as PostPublishAppProps;
await authApp({ appId, req, per: 'w', authToken: true });
const { nodes: formatNodes } = beforeUpdateAppFormat({ nodes });
const { scheduledTriggerConfig } = splitGuideModule(getGuideModule(formatNodes || []));
await mongoSessionRun(async (session) => {
// create version histories
await MongoAppVersion.create(
@@ -28,7 +25,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
{
appId,
nodes: formatNodes,
edges
edges,
chatConfig
}
],
{ session }
@@ -38,12 +36,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
await MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes,
edges,
chatConfig,
updateTime: new Date(),
version: 'v2',
type,
scheduledTriggerConfig,
scheduledTriggerNextTime: scheduledTriggerConfig
? getNextTimeByCronStringAndTimezone(scheduledTriggerConfig)
scheduledTriggerConfig: chatConfig?.scheduledTriggerConfig,
scheduledTriggerNextTime: chatConfig?.scheduledTriggerConfig
? getNextTimeByCronStringAndTimezone(chatConfig.scheduledTriggerConfig)
: null
});
});

View File

@@ -1,11 +1,10 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { PostRevertAppProps } from '@/global/core/app/api';
@@ -28,7 +27,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<
const { nodes: formatEditNodes } = beforeUpdateAppFormat({ nodes: editNodes });
const { scheduledTriggerConfig } = splitGuideModule(getGuideModule(version.nodes));
const scheduledTriggerConfig = version.chatConfig.scheduledTriggerConfig;
await mongoSessionRun(async (session) => {
// 为编辑中的数据创建一个版本

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
@@ -61,10 +61,12 @@ async function handler(
variables: chat?.variables || {},
history,
app: {
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
chatConfig: getAppChatConfig({
chatConfig: app.chatConfig,
systemConfigNode: getGuideModule(nodes),
storeVariables: chat?.variableList,
storeWelcomeText: chat?.welcomeText,
isPublicFetch: false
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,

View File

@@ -0,0 +1,30 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
export type countChatInputGuideTotalQuery = { appId: string };
export type countChatInputGuideTotalBody = {};
export type countChatInputGuideTotalResponse = { total: number };
async function handler(
req: ApiRequestProps<countChatInputGuideTotalBody, countChatInputGuideTotalQuery>,
res: ApiResponseType<any>
): Promise<countChatInputGuideTotalResponse> {
await authCert({ req, authToken: true });
const appId = req.query.appId;
if (!appId) {
return {
total: 0
};
}
return {
total: await MongoChatInputGuide.countDocuments({ appId })
};
}
export default NextAPI(handler);

View File

@@ -0,0 +1,45 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
export type createChatInputGuideQuery = {};
export type createInputGuideBody = {
appId: string;
textList: string[];
};
export type createInputGuideResponse = {
insertLength: number;
};
async function handler(
req: ApiRequestProps<createInputGuideBody, createChatInputGuideQuery>,
res: ApiResponseType<any>
): Promise<createInputGuideResponse> {
const { appId, textList } = req.body;
await authApp({ req, appId, authToken: true, per: 'r' });
try {
const result = await MongoChatInputGuide.insertMany(
textList.map((text) => ({
appId,
text
})),
{
ordered: false
}
);
return {
insertLength: result.length
};
} catch (error: any) {
const errLength = error.writeErrors?.length ?? textList.length;
return {
insertLength: textList.length - errLength
};
}
}
export default NextAPI(handler);

View File

@@ -0,0 +1,27 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
export type deleteChatInputGuideQuery = {};
export type deleteInputGuideBody = { appId: string; dataIdList: string[] };
export type deleteInputGuideResponse = {};
async function handler(
req: ApiRequestProps<deleteInputGuideBody, deleteChatInputGuideQuery>,
res: ApiResponseType<any>
): Promise<deleteInputGuideResponse> {
const { appId, dataIdList } = req.body;
await authApp({ req, appId, authToken: true, per: 'r' });
console.log(dataIdList);
await MongoChatInputGuide.deleteMany({
_id: { $in: dataIdList },
appId
});
return {};
}
export default NextAPI(handler);

View File

@@ -0,0 +1,42 @@
import type { NextApiResponse } from 'next';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { ChatInputGuideSchemaType } from '@fastgpt/global/core/chat/inputGuide/type';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
export type ChatInputGuideProps = PaginationProps<{
appId: string;
searchKey: string;
}>;
export type ChatInputGuideResponse = PaginationResponse<ChatInputGuideSchemaType>;
async function handler(
req: ApiRequestProps<{}, ChatInputGuideProps>,
res: NextApiResponse<any>
): Promise<ChatInputGuideResponse> {
const { appId, pageSize, current, searchKey } = req.query;
await authApp({ req, appId, authToken: true, per: 'r' });
const params = {
appId,
...(searchKey && { text: { $regex: new RegExp(searchKey, 'i') } })
};
const [result, total] = await Promise.all([
MongoChatInputGuide.find(params)
.sort({ _id: -1 })
.skip(pageSize * (current - 1))
.limit(pageSize),
MongoChatInputGuide.countDocuments(params)
]);
return {
list: result,
total
};
}
export default NextAPI(handler);

View File

@@ -0,0 +1,34 @@
import type { NextApiResponse } from 'next';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
import { NextAPI } from '@/service/middleware/entry';
import { ApiRequestProps } from '@fastgpt/service/type/next';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
export type QueryChatInputGuideProps = {
appId: string;
searchKey: string;
};
export type QueryChatInputGuideResponse = string[];
async function handler(
req: ApiRequestProps<{}, QueryChatInputGuideProps>,
res: NextApiResponse<any>
): Promise<QueryChatInputGuideResponse> {
const { appId, searchKey } = req.query;
await authApp({ req, appId, authToken: true, authApiKey: true, per: 'r' });
const params = {
appId,
...(searchKey && { text: { $regex: new RegExp(searchKey, 'i') } })
};
const result = await MongoChatInputGuide.find(params).sort({ _id: -1 }).limit(6);
return result
.map((item) => item.text)
.filter(Boolean)
.filter((item) => item !== searchKey);
}
export default NextAPI(handler);

View File

@@ -0,0 +1,36 @@
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { MongoChatInputGuide } from '@fastgpt/service/core/chat/inputGuide/schema';
export type updateChatInputGuideQuery = {};
export type updateInputGuideBody = {
appId: string;
dataId: string;
text: string;
};
export type updateInputGuideResponse = {};
async function handler(
req: ApiRequestProps<updateInputGuideBody, updateChatInputGuideQuery>,
res: ApiResponseType<any>
): Promise<updateInputGuideResponse> {
const { appId, dataId, text } = req.body;
await authApp({ req, appId, authToken: true, per: 'r' });
await MongoChatInputGuide.findOneAndUpdate(
{
_id: dataId,
appId
},
{
text
}
);
return {};
}
export default NextAPI(handler);

View File

@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
@@ -72,10 +72,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
variables: chat?.variables || {},
history,
app: {
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
chatConfig: getAppChatConfig({
chatConfig: app.chatConfig,
systemConfigNode: getGuideModule(nodes),
storeVariables: chat?.variableList,
storeWelcomeText: chat?.welcomeText,
isPublicFetch: false
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
@@ -73,10 +73,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
variables: chat?.variables || {},
history,
app: {
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
chatConfig: getAppChatConfig({
chatConfig: app.chatConfig,
systemConfigNode: getGuideModule(nodes),
storeVariables: chat?.variableList,
storeWelcomeText: chat?.welcomeText,
isPublicFetch: false
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,

View File

@@ -1,82 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
if (!appId) {
return jsonRes(res, {
code: 501,
message: "You don't have an app yet"
});
}
// auth app permission
const [{ app, tmbId }, chat] = await Promise.all([
authApp({
req,
authToken: true,
appId,
per: 'r'
}),
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
]);
// // auth chat permission
// if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
// throw new Error(ChatErrEnum.unAuthChat);
// }
// get app and history
const { history } = await getChatItems({
appId,
chatId,
limit: 30,
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
DispatchNodeResponseKeyEnum.nodeResponse
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
});
jsonRes<InitChatResponse>(res, {
data: {
chatId,
appId,
title: chat?.title || '新对话',
userAvatar: undefined,
variables: chat?.variables || {},
history,
app: {
userGuideModule: getGuideModule(app.modules),
chatModels: getChatModelNameListByModules(app.modules),
name: app.name,
avatar: app.avatar,
intro: app.intro
}
}
});
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}
export const config = {
api: {
responseLimit: '10mb'
}
};

View File

@@ -26,7 +26,7 @@ async function handler(
});
const [rebuildingCount, trainingCount] = await Promise.all([
MongoDatasetData.countDocuments({ teamId, datasetId, rebuilding: true }),
MongoDatasetData.countDocuments({ rebuilding: true, teamId, datasetId }),
MongoDatasetTraining.countDocuments({ teamId, datasetId })
]);

View File

@@ -7,7 +7,6 @@ import { getAIApi } from '@fastgpt/service/core/ai/config';
import { pushWhisperUsage } from '@/service/support/wallet/usage/push';
import { authChatCert } from '@/service/support/permission/auth/chat';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
import { NextAPI } from '@/service/middleware/entry';
@@ -47,14 +46,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
// auth role
const { teamId, tmbId } = await authChatCert({ req, authToken: true });
// auth app
const app = await MongoApp.findById(appId, 'modules').lean();
if (!app) {
throw new Error('app not found');
}
const { whisperConfig } = splitGuideModule(getGuideModule(app?.modules));
if (!whisperConfig?.open) {
throw new Error('Whisper is not open in the app');
}
// const app = await MongoApp.findById(appId, 'modules').lean();
// if (!app) {
// throw new Error('app not found');
// }
// if (!whisperConfig?.open) {
// throw new Error('Whisper is not open in the app');
// }
const ai = getAIApi();

View File

@@ -170,7 +170,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
// 1. get and concat history; 2. get app workflow
const limit = getMaxHistoryLimitFromNodes(app.modules);
const [{ history }, { nodes, edges }] = await Promise.all([
const [{ history }, { nodes, edges, chatConfig }] = await Promise.all([
getChatItems({
appId: app._id,
chatId,
@@ -249,6 +249,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
teamId,
tmbId: tmbId,
nodes,
appChatConfig: chatConfig,
variables: newVariables,
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
shareId,