{"version":3,"file":"postgres.cjs","names":["BaseListChatMessageHistory"],"sources":["../../../src/stores/message/postgres.ts"],"sourcesContent":["import { BaseListChatMessageHistory } from \"@langchain/core/chat_history\";\nimport {\n  BaseMessage,\n  StoredMessage,\n  mapChatMessagesToStoredMessages,\n  mapStoredMessagesToChatMessages,\n} from \"@langchain/core/messages\";\nimport pg from \"pg\";\n\n/**\n * Type definition for the input parameters required when instantiating a\n * PostgresChatMessageHistory object.\n */\nexport type PostgresChatMessageHistoryInput = {\n  /**\n   * Name of the table to use when storing and retrieving chat message\n   */\n  tableName?: string;\n  /**\n   * Session ID to use when storing and retrieving chat message history.\n   */\n  sessionId: string;\n  /**\n   * Configuration object for the Postgres pool. If provided the\n   * PostgresChatMessageHistory object will create a new pool using\n   * the provided configuration. Otherwise it will use the provided\n   * pool.\n   */\n  poolConfig?: pg.PoolConfig;\n  /**\n   * Postgres pool to use. If provided the PostgresChatMessageHistory\n   * object will use the provided pool. Otherwise it will create a\n   * new pool using the provided configuration.\n   */\n  pool?: pg.Pool;\n  /**\n   * If true, the table name will be escaped. ('lAnGcHaIn' will be escaped to '\"lAnGcHaIn\"')\n   */\n  escapeTableName?: boolean;\n};\n\nexport interface StoredPostgresMessageData {\n  name: string | undefined;\n  role: string | undefined;\n  content: string;\n  additional_kwargs?: Record<string, unknown>;\n  type: string;\n  tool_call_id: string | undefined;\n}\n\n/**\n * Class for managing chat message history using a Postgres Database as a\n * storage backend. Extends the BaseListChatMessageHistory class.\n * @example\n * ```typescript\n * const chatHistory = new PostgresChatMessageHistory({\n *    tableName: \"langchain_chat_histories\",\n *    sessionId: \"lc-example\",\n *    pool: new pg.Pool({\n *      host: \"127.0.0.1\",\n *      port: 5432,\n *      user: \"myuser\",\n *      password: \"ChangeMe\",\n *      database: \"api\",\n *    }),\n * });\n * ```\n */\nexport class PostgresChatMessageHistory extends BaseListChatMessageHistory {\n  lc_namespace = [\"langchain\", \"stores\", \"message\", \"postgres\"];\n\n  pool: pg.Pool;\n\n  tableName = \"langchain_chat_histories\";\n\n  sessionId: string;\n\n  private initialized = false;\n\n  /**\n   * Creates a new PostgresChatMessageHistory.\n   * @param {PostgresChatMessageHistoryInput} fields The input fields for the PostgresChatMessageHistory.\n   * @param {string} fields.tableName The name of the table name to use. Defaults to `langchain_chat_histories`.\n   * @param {string} fields.sessionId The session ID to use when storing and retrieving chat message history.\n   * @param {pg.Pool} fields.pool The Postgres pool to use. If provided, the PostgresChatMessageHistory will use the provided pool.\n   * @param {pg.PoolConfig} fields.poolConfig The configuration object for the Postgres pool. If no pool is provided, the conig will be used to create a new pool.\n   * If `pool` is provided, it will be used as the Postgres pool even if `poolConfig` is also provided.\n   * @throws If neither `pool` nor `poolConfig` is provided.\n   */\n  constructor(fields: PostgresChatMessageHistoryInput) {\n    super(fields);\n    const { tableName, sessionId, pool, poolConfig, escapeTableName } = fields;\n    // Ensure that either a client or config is provided\n    if (!pool && !poolConfig) {\n      throw new Error(\n        \"PostgresChatMessageHistory requires either a pool instance or pool config\"\n      );\n    }\n    this.pool = pool ?? new pg.Pool(poolConfig);\n    const _tableName = tableName || this.tableName;\n    this.tableName = escapeTableName\n      ? pg.escapeIdentifier(_tableName)\n      : _tableName;\n    this.sessionId = sessionId;\n  }\n\n  /**\n   * Checks if the table has been created and creates it if it hasn't.\n   * @returns Promise that resolves when the table's existence is ensured.\n   */\n  private async ensureTable(): Promise<void> {\n    if (this.initialized) return;\n\n    const query = `\n        CREATE TABLE IF NOT EXISTS ${this.tableName} (\n            id SERIAL PRIMARY KEY,\n            session_id VARCHAR(255) NOT NULL,\n            message JSONB NOT NULL\n        );`;\n\n    try {\n      await this.pool.query(query);\n      // oxlint-disable-next-line typescript/no-explicit-any\n    } catch (e: any) {\n      // This error indicates that the table already exists\n      // Due to asynchronous nature of the code, it is possible that\n      // the table is created between the time we check if it exists\n      // and the time we try to create it. It can be safely ignored.\n      // If it's not this error, rethrow it.\n      if (!(\"code\" in e) || e.code !== \"23505\") {\n        throw e;\n      }\n    }\n    this.initialized = true;\n  }\n\n  async addMessage(message: BaseMessage): Promise<void> {\n    await this.ensureTable();\n    const { data, type } = mapChatMessagesToStoredMessages([message])[0];\n\n    const query = `INSERT INTO ${this.tableName} (session_id, message) VALUES ($1, $2)`;\n\n    await this.pool.query(query, [this.sessionId, { ...data, type }]);\n  }\n\n  async getMessages(): Promise<BaseMessage[]> {\n    await this.ensureTable();\n\n    const query = `SELECT message FROM ${this.tableName} WHERE session_id = $1 ORDER BY id`;\n\n    const res = await this.pool.query(query, [this.sessionId]);\n\n    const storedMessages: StoredMessage[] = res.rows.map(\n      (row: { message: StoredPostgresMessageData }) => {\n        const { type, ...data } = row.message;\n        return { type, data };\n      }\n    );\n    return mapStoredMessagesToChatMessages(storedMessages);\n  }\n\n  async clear(): Promise<void> {\n    await this.ensureTable();\n\n    const query = `DELETE FROM ${this.tableName} WHERE session_id = $1`;\n    await this.pool.query(query, [this.sessionId]);\n  }\n\n  /**\n   * End the Postgres pool.\n   */\n  async end(): Promise<void> {\n    await this.pool.end();\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,IAAa,6BAAb,cAAgDA,6BAAAA,2BAA2B;CACzE,eAAe;EAAC;EAAa;EAAU;EAAW;EAAW;CAE7D;CAEA,YAAY;CAEZ;CAEA,cAAsB;;;;;;;;;;;CAYtB,YAAY,QAAyC;AACnD,QAAM,OAAO;EACb,MAAM,EAAE,WAAW,WAAW,MAAM,YAAY,oBAAoB;AAEpE,MAAI,CAAC,QAAQ,CAAC,WACZ,OAAM,IAAI,MACR,4EACD;AAEH,OAAK,OAAO,QAAQ,IAAI,GAAA,QAAG,KAAK,WAAW;EAC3C,MAAM,aAAa,aAAa,KAAK;AACrC,OAAK,YAAY,kBACb,GAAA,QAAG,iBAAiB,WAAW,GAC/B;AACJ,OAAK,YAAY;;;;;;CAOnB,MAAc,cAA6B;AACzC,MAAI,KAAK,YAAa;EAEtB,MAAM,QAAQ;qCACmB,KAAK,UAAU;;;;;AAMhD,MAAI;AACF,SAAM,KAAK,KAAK,MAAM,MAAM;WAErB,GAAQ;AAMf,OAAI,EAAE,UAAU,MAAM,EAAE,SAAS,QAC/B,OAAM;;AAGV,OAAK,cAAc;;CAGrB,MAAM,WAAW,SAAqC;AACpD,QAAM,KAAK,aAAa;EACxB,MAAM,EAAE,MAAM,UAAA,GAAA,yBAAA,iCAAyC,CAAC,QAAQ,CAAC,CAAC;EAElE,MAAM,QAAQ,eAAe,KAAK,UAAU;AAE5C,QAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,WAAW;GAAE,GAAG;GAAM;GAAM,CAAC,CAAC;;CAGnE,MAAM,cAAsC;AAC1C,QAAM,KAAK,aAAa;EAExB,MAAM,QAAQ,uBAAuB,KAAK,UAAU;AAUpD,UAAA,GAAA,yBAAA,kCARY,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,UAAU,CAAC,EAEd,KAAK,KAC9C,QAAgD;GAC/C,MAAM,EAAE,MAAM,GAAG,SAAS,IAAI;AAC9B,UAAO;IAAE;IAAM;IAAM;IAExB,CACqD;;CAGxD,MAAM,QAAuB;AAC3B,QAAM,KAAK,aAAa;EAExB,MAAM,QAAQ,eAAe,KAAK,UAAU;AAC5C,QAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,UAAU,CAAC;;;;;CAMhD,MAAM,MAAqB;AACzB,QAAM,KAAK,KAAK,KAAK"}