{"version":3,"file":"nosql.cjs","names":["BaseListChatMessageHistory","CosmosClient","DefaultAzureCredential"],"sources":["../../src/chat_histories/nosql.ts"],"sourcesContent":["import {\n  Container,\n  CosmosClient,\n  CosmosClientOptions,\n  ErrorResponse,\n} from \"@azure/cosmos\";\nimport { DefaultAzureCredential, TokenCredential } from \"@azure/identity\";\nimport { BaseListChatMessageHistory } from \"@langchain/core/chat_history\";\nimport {\n  BaseMessage,\n  mapChatMessagesToStoredMessages,\n  mapStoredMessagesToChatMessages,\n} from \"@langchain/core/messages\";\nimport { getEnvironmentVariable } from \"@langchain/core/utils/env\";\n\nconst USER_AGENT_SUFFIX = \"langchainjs-cdbnosql-chathistory-javascript\";\nconst DEFAULT_DATABASE_NAME = \"chatHistoryDB\";\nconst DEFAULT_CONTAINER_NAME = \"chatHistoryContainer\";\n\n/**\n * Lightweight type for listing chat sessions.\n */\nexport type ChatSession = {\n  id: string;\n  context: Record<string, unknown>;\n};\n\n/**\n * Type for the input to the `AzureCosmosDBNoSQLChatMessageHistory` constructor.\n */\nexport interface AzureCosmosDBNoSQLChatMessageHistoryInput {\n  sessionId: string;\n  userId?: string;\n  client?: CosmosClient;\n  connectionString?: string;\n  endpoint?: string;\n  databaseName?: string;\n  containerName?: string;\n  credentials?: TokenCredential;\n  ttl?: number;\n}\n\n/**\n * Class for storing chat message history with Cosmos DB NoSQL. It extends the\n * BaseListChatMessageHistory class and provides methods to get, add, and\n * clear messages.\n *\n * @example\n * ```typescript\n *  const model = new ChatOpenAI({\n *   model: \"gpt-3.5-turbo\",\n *   temperature: 0,\n * });\n * const prompt = ChatPromptTemplate.fromMessages([\n *   [\n *     \"system\",\n *     \"You are a helpful assistant. Answer all questions to the best of your ability.\",\n *   ],\n *   new MessagesPlaceholder(\"chat_history\"),\n *   [\"human\", \"{input}\"],\n * ]);\n *\n * const chain = prompt.pipe(model).pipe(new StringOutputParser());\n * const chainWithHistory = new RunnableWithMessageHistory({\n *   runnable: chain,\n *  inputMessagesKey: \"input\",\n *  historyMessagesKey: \"chat_history\",\n *   getMessageHistory: async (sessionId) => {\n *     const chatHistory = new AzureCosmsosDBNoSQLChatMessageHistory({\n *       sessionId: sessionId,\n *       userId: \"user-id\",\n *       databaseName: \"DATABASE_NAME\",\n *       containerName: \"CONTAINER_NAME\",\n *     })\n *     return chatHistory;\n *   },\n * });\n * await chainWithHistory.invoke(\n *   { input: \"What did I just say my name was?\" },\n *   { configurable: { sessionId: \"session-id\" } }\n * );\n * ```\n */\nexport class AzureCosmsosDBNoSQLChatMessageHistory extends BaseListChatMessageHistory {\n  lc_namespace = [\"langchain\", \"stores\", \"message\", \"azurecosmosdb\"];\n\n  private container: Container;\n\n  private sessionId: string;\n\n  private databaseName: string;\n\n  private containerName: string;\n\n  private client: CosmosClient;\n\n  private userId: string;\n\n  private ttl: number | undefined;\n\n  private messageList: BaseMessage[] = [];\n\n  private initPromise?: Promise<void>;\n\n  private context: Record<string, unknown> = {};\n\n  constructor(chatHistoryInput: AzureCosmosDBNoSQLChatMessageHistoryInput) {\n    super();\n\n    this.sessionId = chatHistoryInput.sessionId;\n    this.databaseName = chatHistoryInput.databaseName ?? DEFAULT_DATABASE_NAME;\n    this.containerName =\n      chatHistoryInput.containerName ?? DEFAULT_CONTAINER_NAME;\n    this.userId = chatHistoryInput.userId ?? \"anonymous\";\n    this.ttl = chatHistoryInput.ttl;\n    this.client = this.initializeClient(chatHistoryInput);\n  }\n\n  private initializeClient(\n    input: AzureCosmosDBNoSQLChatMessageHistoryInput\n  ): CosmosClient {\n    const connectionString =\n      input.connectionString ??\n      getEnvironmentVariable(\"AZURE_COSMOSDB_NOSQL_CONNECTION_STRING\");\n    const endpoint =\n      input.endpoint ?? getEnvironmentVariable(\"AZURE_COSMOSDB_NOSQL_ENDPOINT\");\n\n    if (!input.client && !connectionString && !endpoint) {\n      throw new Error(\n        \"CosmosClient, connection string, or endpoint must be provided.\"\n      );\n    }\n\n    if (input.client) {\n      return input.client;\n    }\n\n    if (connectionString) {\n      const [endpointPart, keyPart] = connectionString.split(\";\");\n      const endpoint = endpointPart.split(\"=\")[1];\n      const key = keyPart.split(\"=\")[1];\n\n      return new CosmosClient({\n        endpoint,\n        key,\n        userAgentSuffix: USER_AGENT_SUFFIX,\n      });\n    } else {\n      return new CosmosClient({\n        endpoint,\n        aadCredentials: input.credentials ?? new DefaultAzureCredential(),\n        userAgentSuffix: USER_AGENT_SUFFIX,\n      } as CosmosClientOptions);\n    }\n  }\n\n  private async initializeContainer(): Promise<void> {\n    if (!this.initPromise) {\n      this.initPromise = (async () => {\n        const { database } = await this.client.databases.createIfNotExists({\n          id: this.databaseName,\n        });\n        const { container } = await database.containers.createIfNotExists({\n          id: this.containerName,\n          partitionKey: \"/userId\",\n          defaultTtl: this.ttl,\n        });\n        this.container = container;\n      })().catch((error) => {\n        console.error(\"Error initializing Cosmos DB container:\", error);\n        throw error;\n      });\n    }\n    return this.initPromise;\n  }\n\n  async getMessages(): Promise<BaseMessage[]> {\n    await this.initializeContainer();\n    const document = await this.container\n      .item(this.sessionId, this.userId)\n      .read();\n    const messages = document.resource?.messages || [];\n    this.messageList = mapStoredMessagesToChatMessages(messages);\n    return this.messageList;\n  }\n\n  async addMessage(message: BaseMessage): Promise<void> {\n    await this.addMessages([message]);\n  }\n\n  async addMessages(messages: BaseMessage[]): Promise<void> {\n    await this.initializeContainer();\n    this.messageList = await this.getMessages();\n    this.messageList.push(...messages);\n    const storedMessages = mapChatMessagesToStoredMessages(this.messageList);\n    const context = await this.getContext();\n    await this.container.items.upsert({\n      id: this.sessionId,\n      userId: this.userId,\n      context,\n      messages: storedMessages,\n    });\n  }\n\n  async clear(): Promise<void> {\n    this.messageList = [];\n    await this.initializeContainer();\n    await this.container.item(this.sessionId, this.userId).delete();\n  }\n\n  async clearAllSessions() {\n    await this.initializeContainer();\n    const query = {\n      query: \"SELECT c.id FROM c WHERE c.userId = @userId\",\n      parameters: [{ name: \"@userId\", value: this.userId }],\n    };\n    const { resources: userSessions } = await this.container.items\n      .query(query)\n      .fetchAll();\n    for (const userSession of userSessions) {\n      await this.container.item(userSession.id, this.userId).delete();\n    }\n  }\n\n  async getAllSessions(): Promise<ChatSession[]> {\n    await this.initializeContainer();\n    const query = {\n      query: \"SELECT c.id, c.context FROM c WHERE c.userId = @userId\",\n      parameters: [{ name: \"@userId\", value: this.userId }],\n    };\n    const { resources: userSessions } = await this.container.items\n      .query(query)\n      .fetchAll();\n    return userSessions ?? [];\n  }\n\n  async getContext(): Promise<Record<string, unknown>> {\n    await this.initializeContainer();\n    const document = await this.container\n      .item(this.sessionId, this.userId)\n      .read();\n    this.context = document.resource?.context || this.context;\n    return this.context;\n  }\n\n  async setContext(context: Record<string, unknown>): Promise<void> {\n    await this.initializeContainer();\n    this.context = context || {};\n    try {\n      await this.container\n        .item(this.sessionId, this.userId)\n        .patch([{ op: \"replace\", path: \"/context\", value: this.context }]);\n    } catch (_error: unknown) {\n      const error = _error as ErrorResponse;\n      // If document does not exist yet, context will be set when adding the first message\n      if (error?.code !== 404) {\n        throw error;\n      }\n    }\n  }\n}\n"],"mappings":"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"}