Skip to content

Commit

Permalink
Feature/Add dedicated agent memory nodes (#3649)
Browse files Browse the repository at this point in the history
add dedicated agent memory nodes
  • Loading branch information
HenryHengZJ authored Dec 6, 2024
1 parent fe2ed26 commit cadc3b8
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 15 deletions.
7 changes: 4 additions & 3 deletions packages/components/nodes/memory/AgentMemory/AgentMemory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import path from 'path'
import { getBaseClasses, getCredentialData, getCredentialParam, getUserHome } from '../../../src/utils'
import { SaverOptions } from './interface'
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeParams } from '../../../src/Interface'
import { SqliteSaver } from './sqliteSaver'
import { SqliteSaver } from './SQLiteAgentMemory/sqliteSaver'
import { DataSource } from 'typeorm'
import { PostgresSaver } from './pgSaver'
import { MySQLSaver } from './mysqlSaver'
import { PostgresSaver } from './PostgresAgentMemory/pgSaver'
import { MySQLSaver } from './MySQLAgentMemory/mysqlSaver'

class AgentMemory_Memory implements INode {
label: string
Expand All @@ -29,6 +29,7 @@ class AgentMemory_Memory implements INode {
this.category = 'Memory'
this.description = 'Memory for agentflow to remember the state of the conversation'
this.baseClasses = [this.type, ...getBaseClasses(SqliteSaver)]
this.badge = 'DEPRECATING'
this.credential = {
label: 'Connect Credential',
name: 'credential',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../../src/utils'
import { SaverOptions } from '../interface'
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeParams } from '../../../../src/Interface'
import { DataSource } from 'typeorm'
import { MySQLSaver } from './mysqlSaver'

class MySQLAgentMemory_Memory implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
badge: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams

constructor() {
this.label = 'MySQL Agent Memory'
this.name = 'mySQLAgentMemory'
this.version = 1.0
this.type = 'AgentMemory'
this.icon = 'mysql.png'
this.category = 'Memory'
this.description = 'Memory for agentflow to remember the state of the conversation using MySQL database'
this.baseClasses = [this.type, ...getBaseClasses(MySQLSaver)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['MySQLApi'],
optional: true
}
this.inputs = [
{
label: 'Host',
name: 'host',
type: 'string'
},
{
label: 'Database',
name: 'database',
type: 'string'
},
{
label: 'Port',
name: 'port',
type: 'number',
default: '3306'
},
{
label: 'Additional Connection Configuration',
name: 'additionalConfig',
type: 'json',
additionalParams: true,
optional: true
}
]
}

async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const additionalConfig = nodeData.inputs?.additionalConfig as string
const databaseEntities = options.databaseEntities as IDatabaseEntity
const chatflowid = options.chatflowid as string
const appDataSource = options.appDataSource as DataSource

let additionalConfiguration = {}
if (additionalConfig) {
try {
additionalConfiguration = typeof additionalConfig === 'object' ? additionalConfig : JSON.parse(additionalConfig)
} catch (exception) {
throw new Error('Invalid JSON in the Additional Configuration: ' + exception)
}
}

const threadId = options.sessionId || options.chatId

let datasourceOptions: ICommonObject = {
...additionalConfiguration,
type: 'mysql'
}

const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const user = getCredentialParam('user', credentialData, nodeData)
const password = getCredentialParam('password', credentialData, nodeData)
const _port = (nodeData.inputs?.port as string) || '3306'
const port = parseInt(_port)
datasourceOptions = {
...datasourceOptions,
host: nodeData.inputs?.host as string,
port,
database: nodeData.inputs?.database as string,
username: user,
user: user,
password: password,
charset: 'utf8mb4'
}
const args: SaverOptions = {
datasourceOptions,
threadId,
appDataSource,
databaseEntities,
chatflowid
}
const recordManager = new MySQLSaver(args)
return recordManager
}
}

module.exports = { nodeClass: MySQLAgentMemory_Memory }
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata } from '@langchain/
import { RunnableConfig } from '@langchain/core/runnables'
import { BaseMessage } from '@langchain/core/messages'
import { DataSource } from 'typeorm'
import { CheckpointTuple, SaverOptions, SerializerProtocol } from './interface'
import { IMessage, MemoryMethods } from '../../../src/Interface'
import { mapChatMessageToBaseMessage } from '../../../src/utils'
import { CheckpointTuple, SaverOptions, SerializerProtocol } from '../interface'
import { IMessage, MemoryMethods } from '../../../../src/Interface'
import { mapChatMessageToBaseMessage } from '../../../../src/utils'

export class MySQLSaver extends BaseCheckpointSaver implements MemoryMethods {
protected isSetup: boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../../src/utils'
import { SaverOptions } from '../interface'
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeParams } from '../../../../src/Interface'
import { DataSource } from 'typeorm'
import { PostgresSaver } from './pgSaver'

class PostgresAgentMemory_Memory implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
badge: string
baseClasses: string[]
inputs: INodeParams[]
credential: INodeParams

constructor() {
this.label = 'Postgres Agent Memory'
this.name = 'postgresAgentMemory'
this.version = 1.0
this.type = 'AgentMemory'
this.icon = 'postgres.svg'
this.category = 'Memory'
this.description = 'Memory for agentflow to remember the state of the conversation using Postgres database'
this.baseClasses = [this.type, ...getBaseClasses(PostgresSaver)]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['PostgresApi'],
optional: true
}
this.inputs = [
{
label: 'Host',
name: 'host',
type: 'string'
},
{
label: 'Database',
name: 'database',
type: 'string'
},
{
label: 'Port',
name: 'port',
type: 'number',
default: '5432'
},
{
label: 'Additional Connection Configuration',
name: 'additionalConfig',
type: 'json',
additionalParams: true,
optional: true
}
]
}

async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const additionalConfig = nodeData.inputs?.additionalConfig as string
const databaseEntities = options.databaseEntities as IDatabaseEntity
const chatflowid = options.chatflowid as string
const appDataSource = options.appDataSource as DataSource

let additionalConfiguration = {}
if (additionalConfig) {
try {
additionalConfiguration = typeof additionalConfig === 'object' ? additionalConfig : JSON.parse(additionalConfig)
} catch (exception) {
throw new Error('Invalid JSON in the Additional Configuration: ' + exception)
}
}

const threadId = options.sessionId || options.chatId

let datasourceOptions: ICommonObject = {
...additionalConfiguration,
type: 'postgres'
}

const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const user = getCredentialParam('user', credentialData, nodeData)
const password = getCredentialParam('password', credentialData, nodeData)
const _port = (nodeData.inputs?.port as string) || '5432'
const port = parseInt(_port)
datasourceOptions = {
...datasourceOptions,
host: nodeData.inputs?.host as string,
port,
database: nodeData.inputs?.database as string,
username: user,
user: user,
password: password
}
const args: SaverOptions = {
datasourceOptions,
threadId,
appDataSource,
databaseEntities,
chatflowid
}
const recordManager = new PostgresSaver(args)
return recordManager
}
}

module.exports = { nodeClass: PostgresAgentMemory_Memory }
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { BaseCheckpointSaver, Checkpoint, CheckpointMetadata } from '@langchain/
import { RunnableConfig } from '@langchain/core/runnables'
import { BaseMessage } from '@langchain/core/messages'
import { DataSource } from 'typeorm'
import { CheckpointTuple, SaverOptions, SerializerProtocol } from './interface'
import { IMessage, MemoryMethods } from '../../../src/Interface'
import { mapChatMessageToBaseMessage } from '../../../src/utils'
import { CheckpointTuple, SaverOptions, SerializerProtocol } from '../interface'
import { IMessage, MemoryMethods } from '../../../../src/Interface'
import { mapChatMessageToBaseMessage } from '../../../../src/utils'

export class PostgresSaver extends BaseCheckpointSaver implements MemoryMethods {
protected isSetup: boolean
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit cadc3b8

Please sign in to comment.