feat: add VSCode launch configuration and enhance debug API handler

This commit is contained in:
sd0ric4
2025-03-23 22:46:52 +08:00
parent 1db39e8907
commit d15c09555c
2 changed files with 170 additions and 11 deletions

39
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev",
"cwd": "${workspaceFolder}/projects/app"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug client-side (Edge)",
"type": "msedge",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev",
"cwd": "${workspaceFolder}/projects/app",
"skipFiles": ["<node_internals>/**"],
"serverReadyAction": {
"action": "debugWithEdge",
"killOnServerStop": true,
"pattern": "- Local:.+(https?://.+)",
"uriFormat": "%s",
"webRoot": "${workspaceFolder}/projects/app"
}
}
]
}

View File

@@ -10,13 +10,50 @@ import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { defaultApp } from '@/web/core/app/constants';
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
import { ChatCompletionMessageParam } from '@fastgpt/global/core/ai/type';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import {
getMaxHistoryLimitFromNodes,
getWorkflowEntryNodeIds,
initWorkflowEdgeStatus,
rewriteNodeOutputByHistories,
storeNodes2RuntimeNodes,
textAdaptGptResponse
} from '@fastgpt/global/core/workflow/runtime/utils';
import { responseWrite } from '@fastgpt/service/common/response';
import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getPluginInputsFromStoreNodes } from '@fastgpt/global/core/app/plugin/utils';
import { UserChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import {
getPluginRunUserQuery,
updatePluginInputByVariables
} from '@fastgpt/global/core/workflow/utils';
import { concatHistories, removeEmptyUserInput } from '@fastgpt/global/core/chat/utils';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise<PostWorkflowDebugResponse> {
const { nodes = [], edges = [], variables = {}, appId } = req.body as PostWorkflowDebugProps;
const {
nodes = [],
edges = [],
appId,
messages = [],
chatId = '',
chatConfig = defaultApp.chatConfig,
responseChatItemId = '' // 在内联类型中添加
} = req.body as PostWorkflowDebugProps & {
messages?: ChatCompletionMessageParam[];
chatId?: string;
responseChatItemId?: string; // 在内联类型中添加
chatConfig?: AppChatConfigType; // 在内联类型中添加
};
let variables = req.body.variables || {};
if (!nodes) {
throw new Error('Prams Error');
}
@@ -27,6 +64,25 @@ async function handler(
throw new Error('Edges is not array');
}
const entryNodeIds = nodes
.filter((node) => node.isEntry)
.map((node) => node.nodeId)
.filter((nodeId) => !!nodeId);
if (entryNodeIds.length === 0) {
throw new Error('No entry node found');
}
if (entryNodeIds.length > 1) {
throw new Error('More than one entry node found');
}
const isInteractiveNode = nodes.some(
(node) =>
node.nodeId === entryNodeIds[0] &&
(node.flowNodeType === 'userSelect' || node.flowNodeType === 'formInput')
);
console.log('isInteractiveNode', isInteractiveNode);
const chatMessages = GPTMessages2Chats(messages);
//
/* user auth */
const [{ teamId, tmbId }, { app }] = await Promise.all([
authCert({
@@ -35,15 +91,79 @@ async function handler(
}),
authApp({ req, authToken: true, appId, per: ReadPermissionVal })
]);
const appName = `${app.name}-Debug`;
// auth balance
const { timezone, externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const isPlugin = app.type === AppTypeEnum.plugin;
let userQuestion: UserChatItemType | undefined;
if (isInteractiveNode) {
userQuestion = (() => {
if (isPlugin) {
return getPluginRunUserQuery({
pluginInputs: getPluginInputsFromStoreNodes(app.modules),
variables,
files: variables.files
});
}
const latestHumanChat = chatMessages.pop() as UserChatItemType | undefined;
if (!latestHumanChat) {
throw new Error('User question is empty');
}
return latestHumanChat;
})();
}
const limit = getMaxHistoryLimitFromNodes(nodes);
const [{ histories }, chatDetail, { timezone, externalProvider }] = await Promise.all([
getChatItems({
appId,
chatId,
offset: 0,
limit,
field: `dataId obj value nodeOutputs`
}),
MongoChat.findOne({ appId: app._id, chatId }, 'source variableList variables'),
// auth balance
getUserChatInfoAndAuthTeamPoints(tmbId)
]);
if (chatDetail?.variables) {
variables = {
...chatDetail.variables,
...variables
};
}
const newHistories = concatHistories(histories, chatMessages);
// Get runtimeNodes
let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories));
if (isPlugin) {
runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables);
variables = {};
}
runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes);
let runtimeEdges = edges;
let query: UserChatItemValueItemType[] = [];
if (isInteractiveNode && userQuestion) {
runtimeEdges = initWorkflowEdgeStatus(edges, newHistories);
query = removeEmptyUserInput(userQuestion.value);
} else if (!isInteractiveNode) {
runtimeEdges = edges;
runtimeNodes = nodes;
query = [];
}
/* start process */
const { flowUsages, flowResponses, debugResponse, newVariables } = await dispatchWorkFlow({
res,
requestOrigin: req.headers.origin,
mode: 'debug',
timezone,
externalProvider,
uid: tmbId,
runningAppInfo: {
id: app._id,
teamId: app.teamId,
@@ -53,21 +173,21 @@ async function handler(
teamId,
tmbId
},
uid: tmbId,
timezone,
externalProvider,
runtimeNodes: nodes,
runtimeEdges: edges,
chatId,
responseChatItemId,
runtimeNodes,
runtimeEdges,
variables,
query: [],
query,
chatConfig: defaultApp.chatConfig,
histories: [],
histories: newHistories,
stream: false,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
});
createChatUsage({
appName: `${app.name}-Debug`,
appName,
appId,
teamId,
tmbId,