Merge branch 'main' into feature/output-parsers

# Conflicts:
#	packages/ui/src/views/chatmessage/ChatMessage.js
This commit is contained in:
Henry
2023-11-03 13:10:06 +00:00
82 changed files with 3193 additions and 444 deletions
+10 -1
View File
@@ -2,6 +2,10 @@ import { ICommonObject, INode, INodeData as INodeDataFromComponent, INodeParams
export type MessageType = 'apiMessage' | 'userMessage'
export enum chatType {
INTERNAL = 'INTERNAL',
EXTERNAL = 'EXTERNAL'
}
/**
* Databases
*/
@@ -24,8 +28,12 @@ export interface IChatMessage {
role: MessageType
content: string
chatflowid: string
createdDate: Date
sourceDocuments?: string
chatType: string
chatId: string
memoryType?: string
sessionId?: string
createdDate: Date
}
export interface ITool {
@@ -146,6 +154,7 @@ export interface IncomingInput {
history: IMessage[]
overrideConfig?: ICommonObject
socketIOClientId?: string
chatId?: string
}
export interface IActiveChatflows {
@@ -20,6 +20,18 @@ export class ChatMessage implements IChatMessage {
@Column({ nullable: true, type: 'text' })
sourceDocuments?: string
@Column()
chatType: string
@Column()
chatId: string
@Column({ nullable: true })
memoryType?: string
@Column({ nullable: true })
sessionId?: string
@CreateDateColumn()
createdDate: Date
}
@@ -2,7 +2,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddApiConfig1694099200729 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`apiConfig\` TEXT;`)
const columnExists = await queryRunner.hasColumn('chat_flow', 'apiConfig')
if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`apiConfig\` TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -2,7 +2,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddAnalytic1694432361423 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`analytic\` TEXT;`)
const columnExists = await queryRunner.hasColumn('chat_flow', 'analytic')
if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`analytic\` TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -0,0 +1,41 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694658767766 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const chatTypeColumnExists = await queryRunner.hasColumn('chat_message', 'chatType')
if (!chatTypeColumnExists)
await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`chatType\` VARCHAR(255) NOT NULL DEFAULT 'INTERNAL';`)
const chatIdColumnExists = await queryRunner.hasColumn('chat_message', 'chatId')
if (!chatIdColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`chatId\` VARCHAR(255);`)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
\`chatflowid\`,
\`id\`,
\`createdDate\`,
ROW_NUMBER() OVER (PARTITION BY \`chatflowid\` ORDER BY \`createdDate\`) AS row_num
FROM \`chat_message\`
)
SELECT \`chatflowid\`, \`id\`
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE \`chat_message\` SET \`chatId\` = '${chatMessage.id}' WHERE \`chatflowid\` = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(`ALTER TABLE \`chat_message\` MODIFY \`chatId\` VARCHAR(255) NOT NULL;`)
const memoryTypeColumnExists = await queryRunner.hasColumn('chat_message', 'memoryType')
if (!memoryTypeColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`memoryType\` VARCHAR(255);`)
const sessionIdColumnExists = await queryRunner.hasColumn('chat_message', 'sessionId')
if (!sessionIdColumnExists) await queryRunner.query(`ALTER TABLE \`chat_message\` ADD COLUMN \`sessionId\` VARCHAR(255);`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE \`chat_message\` DROP COLUMN \`chatType\`, DROP COLUMN \`chatId\`, DROP COLUMN \`memoryType\`, DROP COLUMN \`sessionId\`;`
)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693999261583 } from './1693999261583-ModifyCredential'
import { ModifyTool1694001465232 } from './1694001465232-ModifyTool'
import { AddApiConfig1694099200729 } from './1694099200729-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694658767766 } from './1694658767766-AddChatHistory'
export const mysqlMigrations = [
Init1693840429259,
@@ -13,5 +14,6 @@ export const mysqlMigrations = [
ModifyCredential1693999261583,
ModifyTool1694001465232,
AddApiConfig1694099200729,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694658767766
]
@@ -2,7 +2,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddApiConfig1694099183389 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "apiConfig" TEXT;`)
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "apiConfig" TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -2,7 +2,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddAnalytic1694432361423 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "analytic" TEXT;`)
await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "analytic" TEXT;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
@@ -0,0 +1,32 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694658756136 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "chat_message" ADD COLUMN IF NOT EXISTS "chatType" VARCHAR NOT NULL DEFAULT 'INTERNAL', ADD COLUMN IF NOT EXISTS "chatId" VARCHAR, ADD COLUMN IF NOT EXISTS "memoryType" VARCHAR, ADD COLUMN IF NOT EXISTS "sessionId" VARCHAR;`
)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
"chatflowid",
"id",
"createdDate",
ROW_NUMBER() OVER (PARTITION BY "chatflowid" ORDER BY "createdDate") AS row_num
FROM "chat_message"
)
SELECT "chatflowid", "id"
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE "chat_message" SET "chatId" = '${chatMessage.id}' WHERE "chatflowid" = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(`ALTER TABLE "chat_message" ALTER COLUMN "chatId" SET NOT NULL;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "chat_message" DROP COLUMN "chatType", DROP COLUMN "chatId", DROP COLUMN "memoryType", DROP COLUMN "sessionId";`
)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693997070000 } from './1693997070000-ModifyCredential'
import { ModifyTool1693997339912 } from './1693997339912-ModifyTool'
import { AddApiConfig1694099183389 } from './1694099183389-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694658756136 } from './1694658756136-AddChatHistory'
export const postgresMigrations = [
Init1693891895163,
@@ -13,5 +14,6 @@ export const postgresMigrations = [
ModifyCredential1693997070000,
ModifyTool1693997339912,
AddApiConfig1694099183389,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694658756136
]
@@ -0,0 +1,40 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class AddChatHistory1694657778173 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "chat_message" ADD COLUMN "chatId" VARCHAR;`)
const results: { id: string; chatflowid: string }[] = await queryRunner.query(`WITH RankedMessages AS (
SELECT
"chatflowid",
"id",
"createdDate",
ROW_NUMBER() OVER (PARTITION BY "chatflowid" ORDER BY "createdDate") AS row_num
FROM "chat_message"
)
SELECT "chatflowid", "id"
FROM RankedMessages
WHERE row_num = 1;`)
for (const chatMessage of results) {
await queryRunner.query(
`UPDATE "chat_message" SET "chatId" = '${chatMessage.id}' WHERE "chatflowid" = '${chatMessage.chatflowid}'`
)
}
await queryRunner.query(
`CREATE TABLE "temp_chat_message" ("id" varchar PRIMARY KEY NOT NULL, "role" varchar NOT NULL, "chatflowid" varchar NOT NULL, "content" text NOT NULL, "sourceDocuments" text, "createdDate" datetime NOT NULL DEFAULT (datetime('now')), "chatType" VARCHAR NOT NULL DEFAULT 'INTERNAL', "chatId" VARCHAR NOT NULL, "memoryType" VARCHAR, "sessionId" VARCHAR);`
)
await queryRunner.query(
`INSERT INTO "temp_chat_message" ("id", "role", "chatflowid", "content", "sourceDocuments", "createdDate", "chatId") SELECT "id", "role", "chatflowid", "content", "sourceDocuments", "createdDate", "chatId" FROM "chat_message";`
)
await queryRunner.query(`DROP TABLE "chat_message";`)
await queryRunner.query(`ALTER TABLE "temp_chat_message" RENAME TO "chat_message";`)
await queryRunner.query(`CREATE INDEX "IDX_e574527322272fd838f4f0f3d3" ON "chat_message" ("chatflowid") ;`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE IF EXISTS "temp_chat_message";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "chatType";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "chatId";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "memoryType";`)
await queryRunner.query(`ALTER TABLE "chat_message" DROP COLUMN "sessionId";`)
}
}
@@ -5,6 +5,7 @@ import { ModifyCredential1693923551694 } from './1693923551694-ModifyCredential'
import { ModifyTool1693924207475 } from './1693924207475-ModifyTool'
import { AddApiConfig1694090982460 } from './1694090982460-AddApiConfig'
import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic'
import { AddChatHistory1694657778173 } from './1694657778173-AddChatHistory'
export const sqliteMigrations = [
Init1693835579790,
@@ -13,5 +14,6 @@ export const sqliteMigrations = [
ModifyCredential1693923551694,
ModifyTool1693924207475,
AddApiConfig1694090982460,
AddAnalytic1694432361423
AddAnalytic1694432361423,
AddChatHistory1694657778173
]
+204 -36
View File
@@ -8,7 +8,8 @@ import basicAuth from 'express-basic-auth'
import { Server } from 'socket.io'
import logger from './utils/logger'
import { expressRequestLogger } from './utils/logger'
import { v4 as uuidv4 } from 'uuid'
import { Between, IsNull, FindOptionsWhere } from 'typeorm'
import {
IChatFlow,
IncomingInput,
@@ -16,7 +17,10 @@ import {
IReactFlowObject,
INodeData,
IDatabaseExport,
ICredentialReturnResponse
ICredentialReturnResponse,
chatType,
IChatMessage,
IReactFlowEdge
} from './Interface'
import {
getNodeModulesPackagePath,
@@ -40,10 +44,11 @@ import {
getApiKey,
transformToCredentialEntity,
decryptCredentialData,
clearSessionMemory,
clearAllSessionMemory,
replaceInputsWithConfig,
getEncryptionKey,
checkMemorySessionId
checkMemorySessionId,
clearSessionMemoryFromViewMessageDialog
} from './utils'
import { cloneDeep, omit } from 'lodash'
import { getDataSource } from './DataSource'
@@ -395,45 +400,92 @@ export class App {
// Get all chatmessages from chatflowid
this.app.get('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const chatmessages = await this.AppDataSource.getRepository(ChatMessage).find({
where: {
chatflowid: req.params.id
},
order: {
createdDate: 'ASC'
const sortOrder = req.query?.order as string | undefined
const chatId = req.query?.chatId as string | undefined
const memoryType = req.query?.memoryType as string | undefined
const sessionId = req.query?.sessionId as string | undefined
const startDate = req.query?.startDate as string | undefined
const endDate = req.query?.endDate as string | undefined
let chatTypeFilter = req.query?.chatType as chatType | undefined
if (chatTypeFilter) {
try {
const chatTypeFilterArray = JSON.parse(chatTypeFilter)
if (chatTypeFilterArray.includes(chatType.EXTERNAL) && chatTypeFilterArray.includes(chatType.INTERNAL)) {
chatTypeFilter = undefined
} else if (chatTypeFilterArray.includes(chatType.EXTERNAL)) {
chatTypeFilter = chatType.EXTERNAL
} else if (chatTypeFilterArray.includes(chatType.INTERNAL)) {
chatTypeFilter = chatType.INTERNAL
}
} catch (e) {
return res.status(500).send(e)
}
})
}
const chatmessages = await this.getChatMessage(
req.params.id,
chatTypeFilter,
sortOrder,
chatId,
memoryType,
sessionId,
startDate,
endDate
)
return res.json(chatmessages)
})
// Get internal chatmessages from chatflowid
this.app.get('/api/v1/internal-chatmessage/:id', async (req: Request, res: Response) => {
const chatmessages = await this.getChatMessage(req.params.id, chatType.INTERNAL)
return res.json(chatmessages)
})
// Add chatmessages for chatflowid
this.app.post('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const body = req.body
const newChatMessage = new ChatMessage()
Object.assign(newChatMessage, body)
const chatmessage = this.AppDataSource.getRepository(ChatMessage).create(newChatMessage)
const results = await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
const results = await this.addChatMessage(body)
return res.json(results)
})
// Delete all chatmessages from chatflowid
// Delete all chatmessages from chatId
this.app.delete('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const chatflowid = req.params.id
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
id: req.params.id
id: chatflowid
})
if (!chatflow) {
res.status(404).send(`Chatflow ${req.params.id} not found`)
res.status(404).send(`Chatflow ${chatflowid} not found`)
return
}
const chatId = (req.query?.chatId as string) ?? (await getChatId(chatflowid))
const memoryType = req.query?.memoryType as string | undefined
const sessionId = req.query?.sessionId as string | undefined
const chatType = req.query?.chatType as string | undefined
const isClearFromViewMessageDialog = req.query?.isClearFromViewMessageDialog as string | undefined
const flowData = chatflow.flowData
const parsedFlowData: IReactFlowObject = JSON.parse(flowData)
const nodes = parsedFlowData.nodes
let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = chatflow.id
clearSessionMemory(nodes, this.nodesPool.componentNodes, chatId, this.AppDataSource, req.query.sessionId as string)
const results = await this.AppDataSource.getRepository(ChatMessage).delete({ chatflowid: req.params.id })
if (isClearFromViewMessageDialog)
clearSessionMemoryFromViewMessageDialog(
nodes,
this.nodesPool.componentNodes,
chatId,
this.AppDataSource,
sessionId,
memoryType
)
else clearAllSessionMemory(nodes, this.nodesPool.componentNodes, chatId, this.AppDataSource, sessionId)
const deleteOptions: FindOptionsWhere<ChatMessage> = { chatflowid, chatId }
if (memoryType) deleteOptions.memoryType = memoryType
if (sessionId) deleteOptions.sessionId = sessionId
if (chatType) deleteOptions.chatType = chatType
const results = await this.AppDataSource.getRepository(ChatMessage).delete(deleteOptions)
return res.json(results)
})
@@ -809,18 +861,95 @@ export class App {
* @param {Response} res
* @param {ChatFlow} chatflow
*/
async validateKey(req: Request, res: Response, chatflow: ChatFlow) {
async validateKey(req: Request, chatflow: ChatFlow) {
const chatFlowApiKeyId = chatflow.apikeyid
const authorizationHeader = (req.headers['Authorization'] as string) ?? (req.headers['authorization'] as string) ?? ''
if (!chatFlowApiKeyId) return true
if (chatFlowApiKeyId && !authorizationHeader) return res.status(401).send(`Unauthorized`)
const authorizationHeader = (req.headers['Authorization'] as string) ?? (req.headers['authorization'] as string) ?? ''
if (chatFlowApiKeyId && !authorizationHeader) return false
const suppliedKey = authorizationHeader.split(`Bearer `).pop()
if (chatFlowApiKeyId && suppliedKey) {
if (suppliedKey) {
const keys = await getAPIKeys()
const apiSecret = keys.find((key) => key.id === chatFlowApiKeyId)?.apiSecret
if (!compareKeys(apiSecret, suppliedKey)) return res.status(401).send(`Unauthorized`)
if (!compareKeys(apiSecret, suppliedKey)) return false
return true
}
return false
}
/**
* Method that get chat messages.
* @param {string} chatflowid
* @param {chatType} chatType
* @param {string} sortOrder
* @param {string} chatId
* @param {string} memoryType
* @param {string} sessionId
* @param {string} startDate
* @param {string} endDate
*/
async getChatMessage(
chatflowid: string,
chatType: chatType | undefined,
sortOrder: string = 'ASC',
chatId?: string,
memoryType?: string,
sessionId?: string,
startDate?: string,
endDate?: string
): Promise<ChatMessage[]> {
let fromDate
if (startDate) fromDate = new Date(startDate)
let toDate
if (endDate) toDate = new Date(endDate)
return await this.AppDataSource.getRepository(ChatMessage).find({
where: {
chatflowid,
chatType,
chatId,
memoryType: memoryType ?? (chatId ? IsNull() : undefined),
sessionId: sessionId ?? (chatId ? IsNull() : undefined),
createdDate: toDate && fromDate ? Between(fromDate, toDate) : undefined
},
order: {
createdDate: sortOrder === 'DESC' ? 'DESC' : 'ASC'
}
})
}
/**
* Method that add chat messages.
* @param {Partial<IChatMessage>} chatMessage
*/
async addChatMessage(chatMessage: Partial<IChatMessage>): Promise<ChatMessage> {
const newChatMessage = new ChatMessage()
Object.assign(newChatMessage, chatMessage)
const chatmessage = this.AppDataSource.getRepository(ChatMessage).create(newChatMessage)
return await this.AppDataSource.getRepository(ChatMessage).save(chatmessage)
}
/**
* Method that find memory label that is connected within chatflow
* In a chatflow, there should only be 1 memory node
* @param {IReactFlowNode[]} nodes
* @param {IReactFlowEdge[]} edges
* @returns {string | undefined}
*/
findMemoryLabel(nodes: IReactFlowNode[], edges: IReactFlowEdge[]): string | undefined {
const memoryNodes = nodes.filter((node) => node.data.category === 'Memory')
const memoryNodeIds = memoryNodes.map((mem) => mem.data.id)
for (const edge of edges) {
if (memoryNodeIds.includes(edge.source)) {
const memoryNode = nodes.find((node) => node.data.id === edge.source)
return memoryNode ? memoryNode.data.label : undefined
}
}
return undefined
}
/**
@@ -830,7 +959,7 @@ export class App {
* @param {Server} socketIO
* @param {boolean} isInternal
*/
async processPrediction(req: Request, res: Response, socketIO?: Server, isInternal = false) {
async processPrediction(req: Request, res: Response, socketIO?: Server, isInternal: boolean = false) {
try {
const chatflowid = req.params.id
let incomingInput: IncomingInput = req.body
@@ -842,11 +971,12 @@ export class App {
})
if (!chatflow) return res.status(404).send(`Chatflow ${chatflowid} not found`)
let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = chatflowid
const chatId = incomingInput.chatId ?? incomingInput.overrideConfig?.sessionId ?? uuidv4()
const userMessageDateTime = new Date()
if (!isInternal) {
await this.validateKey(req, res, chatflow)
const isKeyValidated = await this.validateKey(req, chatflow)
if (!isKeyValidated) return res.status(401).send('Unauthorized')
}
let isStreamValid = false
@@ -978,9 +1108,12 @@ export class App {
logger.debug(`[server]: Running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`)
if (nodeToExecuteData.instance) checkMemorySessionId(nodeToExecuteData.instance, chatId)
let sessionId = undefined
if (nodeToExecuteData.instance) sessionId = checkMemorySessionId(nodeToExecuteData.instance, chatId)
const result = isStreamValid
const memoryType = this.findMemoryLabel(nodes, edges)
let result = isStreamValid
? await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatHistory: incomingInput.history,
socketIO,
@@ -998,7 +1131,42 @@ export class App {
analytic: chatflow.analytic
})
result = typeof result === 'string' ? { text: result } : result
const userMessage: Omit<IChatMessage, 'id'> = {
role: 'userMessage',
content: incomingInput.question,
chatflowid,
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
chatId,
memoryType,
sessionId,
createdDate: userMessageDateTime
}
await this.addChatMessage(userMessage)
let resultText = ''
if (result.text) resultText = result.text
else if (result.json) resultText = '```json\n' + JSON.stringify(result.json, null, 2)
else resultText = JSON.stringify(result, null, 2)
const apiMessage: Omit<IChatMessage, 'id' | 'createdDate'> = {
role: 'apiMessage',
content: resultText,
chatflowid,
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
chatId,
memoryType,
sessionId
}
if (result?.sourceDocuments) apiMessage.sourceDocuments = JSON.stringify(result.sourceDocuments)
await this.addChatMessage(apiMessage)
logger.debug(`[server]: Finished running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`)
// Only return ChatId when its Internal OR incoming input has ChatId, to avoid confusion when calling API
if (incomingInput.chatId || isInternal) result.chatId = chatId
return res.json(result)
} catch (e: any) {
logger.error('[server]: Error:', e)
@@ -1021,7 +1189,7 @@ export class App {
* @param {string} chatflowid
* @returns {string}
*/
export async function getChatId(chatflowid: string) {
export async function getChatId(chatflowid: string): Promise<string> {
// first chatmessage id as the unique chat id
const firstChatMessage = await getDataSource()
.getRepository(ChatMessage)
+43 -4
View File
@@ -298,14 +298,14 @@ export const buildLangchain = async (
}
/**
* Clear memory
* Clear all session memories on the canvas
* @param {IReactFlowNode[]} reactFlowNodes
* @param {IComponentNodes} componentNodes
* @param {string} chatId
* @param {DataSource} appDataSource
* @param {string} sessionId
*/
export const clearSessionMemory = async (
export const clearAllSessionMemory = async (
reactFlowNodes: IReactFlowNode[],
componentNodes: IComponentNodes,
chatId: string,
@@ -317,9 +317,46 @@ export const clearSessionMemory = async (
const nodeInstanceFilePath = componentNodes[node.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory)
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
}
}
}
/**
* Clear specific session memory from View Message Dialog UI
* @param {IReactFlowNode[]} reactFlowNodes
* @param {IComponentNodes} componentNodes
* @param {string} chatId
* @param {DataSource} appDataSource
* @param {string} sessionId
* @param {string} memoryType
*/
export const clearSessionMemoryFromViewMessageDialog = async (
reactFlowNodes: IReactFlowNode[],
componentNodes: IComponentNodes,
chatId: string,
appDataSource: DataSource,
sessionId?: string,
memoryType?: string
) => {
if (!sessionId) return
for (const node of reactFlowNodes) {
if (node.data.category !== 'Memory') continue
if (node.data.label !== memoryType) continue
const nodeInstanceFilePath = componentNodes[node.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
return
}
}
}
@@ -937,8 +974,10 @@ export const redactCredentialWithPasswordType = (
* @param {any} instance
* @param {string} chatId
*/
export const checkMemorySessionId = (instance: any, chatId: string) => {
export const checkMemorySessionId = (instance: any, chatId: string): string => {
if (instance.memory && instance.memory.isSessionIdUsingChatMessageId && chatId) {
instance.memory.sessionId = chatId
instance.memory.chatHistory.sessionId = chatId
}
return instance.memory ? instance.memory.sessionId ?? instance.memory.chatHistory.sessionId : undefined
}