{"version":3,"file":"aurora_dsql.cjs","names":["BaseListChatMessageHistory"],"sources":["../../../src/stores/message/aurora_dsql.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 * AuroraDsqlChatMessageHistory object.\n */\nexport type AuroraDsqlChatMessageHistoryInput = {\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   * AuroraDsqlChatMessageHistory 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 StoredAuroraDsqlMessageData {\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 Amazon Aurora DSQL Database as a\n * storage backend. Extends the BaseListChatMessageHistory class.\n * @example\n * ```typescript\n * const chatHistory = new AuroraDsqlChatMessageHistory({\n *    tableName: \"langchain_chat_histories\",\n *    sessionId: \"lc-example\",\n *    pool: new pg.Pool({\n *      host: \"your_dsql_endpoint\",\n *      port: 5432,\n *      user: \"admin\",\n *      password: \"your_token\",\n *      database: \"postgres\",\n *      ssl: true\n *    }),\n * });\n * ```\n */\nexport class AuroraDsqlChatMessageHistory extends BaseListChatMessageHistory {\n  lc_namespace = [\"langchain\", \"stores\", \"message\", \"aurora_dsql\"];\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 AuroraDsqlChatMessageHistory.\n   * @param {AuroraDsqlChatMessageHistoryInput} fields The input fields for the AuroraDsqlChatMessageHistory.\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 AuroraDsqlChatMessageHistory will use the provided pool.\n   * @param {pg.PoolConfig} fields.poolConfig The configuration object for the Postgres pool. If no pool is provided, the config 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: AuroraDsqlChatMessageHistoryInput) {\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        \"AuroraDsqlChatMessageHistory 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 UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n      created_at timestamp default current_timestamp,\n      session_id VARCHAR(255) NOT NULL,\n      message TEXT NOT NULL\n    );`;\n\n    try {\n      await this.pool.query(query);\n      await this.createIndex();\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  private async createIndex() {\n    const query = `CREATE INDEX ASYNC IF NOT EXISTS idx_on_session_id on ${this.tableName} (session_id);`;\n    await this.pool.query(query);\n  }\n\n  async addMessage(message: BaseMessage): Promise<void> {\n    await this.ensureTable();\n\n    const map = mapChatMessagesToStoredMessages([message])[0];\n\n    const query = `INSERT INTO ${this.tableName} (session_id, message) VALUES ($1, $2)`;\n\n    await this.pool.query(query, [\n      this.sessionId,\n      JSON.stringify({ ...map?.data, type: map?.type }),\n    ]);\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 created_at asc`;\n\n    const res = await this.pool.query(query, [this.sessionId]);\n\n    const storedMessages: StoredMessage[] = res.rows.map(\n      (row: { message: string }) => {\n        const { type, ...data } = JSON.parse(\n          row.message\n        ) as StoredAuroraDsqlMessageData;\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEA,IAAa,+BAAb,cAAkDA,6BAAAA,2BAA2B;CAC3E,eAAe;EAAC;EAAa;EAAU;EAAW;EAAc;CAEhE;CAEA,YAAY;CAEZ;CAEA,cAAsB;;;;;;;;;;;CAYtB,YAAY,QAA2C;AACrD,QAAM,OAAO;EACb,MAAM,EAAE,WAAW,WAAW,MAAM,YAAY,oBAAoB;AAEpE,MAAI,CAAC,QAAQ,CAAC,WACZ,OAAM,IAAI,MACR,8EACD;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;iCACe,KAAK,UAAU;;;;;;AAO5C,MAAI;AACF,SAAM,KAAK,KAAK,MAAM,MAAM;AAC5B,SAAM,KAAK,aAAa;WAEjB,GAAQ;AAMf,OAAI,EAAE,UAAU,MAAM,EAAE,SAAS,QAC/B,OAAM;;AAGV,OAAK,cAAc;;CAGrB,MAAc,cAAc;EAC1B,MAAM,QAAQ,yDAAyD,KAAK,UAAU;AACtF,QAAM,KAAK,KAAK,MAAM,MAAM;;CAG9B,MAAM,WAAW,SAAqC;AACpD,QAAM,KAAK,aAAa;EAExB,MAAM,OAAA,GAAA,yBAAA,iCAAsC,CAAC,QAAQ,CAAC,CAAC;EAEvD,MAAM,QAAQ,eAAe,KAAK,UAAU;AAE5C,QAAM,KAAK,KAAK,MAAM,OAAO,CAC3B,KAAK,WACL,KAAK,UAAU;GAAE,GAAG,KAAK;GAAM,MAAM,KAAK;GAAM,CAAC,CAClD,CAAC;;CAGJ,MAAM,cAAsC;AAC1C,QAAM,KAAK,aAAa;EAExB,MAAM,QAAQ,uBAAuB,KAAK,UAAU;AAYpD,UAAA,GAAA,yBAAA,kCAVY,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,UAAU,CAAC,EAEd,KAAK,KAC9C,QAA6B;GAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAC7B,IAAI,QACL;AACD,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"}