{"version":3,"file":"dynamodb.cjs","names":["BaseListChatMessageHistory","DynamoDBClient","GetItemCommand","UpdateItemCommand","DeleteItemCommand"],"sources":["../../../src/stores/message/dynamodb.ts"],"sourcesContent":["import {\n  DynamoDBClient,\n  DynamoDBClientConfig,\n  GetItemCommand,\n  GetItemCommandInput,\n  UpdateItemCommand,\n  UpdateItemCommandInput,\n  DeleteItemCommand,\n  DeleteItemCommandInput,\n  AttributeValue,\n} from \"@aws-sdk/client-dynamodb\";\n\nimport { BaseListChatMessageHistory } from \"@langchain/core/chat_history\";\nimport {\n  BaseMessage,\n  StoredMessage,\n  mapChatMessagesToStoredMessages,\n  mapStoredMessagesToChatMessages,\n} from \"@langchain/core/messages\";\n\n/**\n * Interface defining the fields required to create an instance of\n * `DynamoDBChatMessageHistory`. It includes the DynamoDB table name,\n * session ID, partition key, sort key, message attribute name, and\n * DynamoDB client configuration.\n */\nexport interface DynamoDBChatMessageHistoryFields {\n  tableName: string;\n  sessionId: string;\n  partitionKey?: string;\n  sortKey?: string;\n  messageAttributeName?: string;\n  config?: DynamoDBClientConfig;\n  key?: Record<string, AttributeValue>;\n}\n\n/**\n * Interface defining the structure of a chat message as it is stored in\n * DynamoDB.\n */\ninterface DynamoDBSerializedChatMessage {\n  M: {\n    type: {\n      S: string;\n    };\n    text: {\n      S: string;\n    };\n    role?: {\n      S: string;\n    };\n    additional_kwargs?: {\n      S: string;\n    };\n  };\n}\n\n/**\n * Class providing methods to interact with a DynamoDB table to store and\n * retrieve chat messages. It extends the `BaseListChatMessageHistory`\n * class.\n */\nexport class DynamoDBChatMessageHistory extends BaseListChatMessageHistory {\n  lc_namespace = [\"langchain\", \"stores\", \"message\", \"dynamodb\"];\n\n  get lc_secrets(): { [key: string]: string } | undefined {\n    return {\n      \"config.credentials.accessKeyId\": \"AWS_ACCESS_KEY_ID\",\n      \"config.credentials.secretAccessKey\": \"AWS_SECRETE_ACCESS_KEY\",\n      \"config.credentials.sessionToken\": \"AWS_SESSION_TOKEN\",\n    };\n  }\n\n  private tableName: string;\n\n  private sessionId: string;\n\n  private client: DynamoDBClient;\n\n  private partitionKey = \"id\";\n\n  private sortKey?: string;\n\n  private messageAttributeName = \"messages\";\n\n  private dynamoKey: Record<string, AttributeValue> = {};\n\n  /**\n   * Transforms a `StoredMessage` into a `DynamoDBSerializedChatMessage`.\n   * The `DynamoDBSerializedChatMessage` format is suitable for storing in DynamoDB.\n   *\n   * @param message - The `StoredMessage` to be transformed.\n   * @returns The transformed `DynamoDBSerializedChatMessage`.\n   */\n  private createDynamoDBSerializedChatMessage(\n    message: StoredMessage\n  ): DynamoDBSerializedChatMessage {\n    const {\n      type,\n      data: { content, role, additional_kwargs },\n    } = message;\n\n    const isAdditionalKwargs =\n      additional_kwargs && Object.keys(additional_kwargs).length;\n\n    const dynamoSerializedMessage: DynamoDBSerializedChatMessage = {\n      M: {\n        type: {\n          S: type,\n        },\n        text: {\n          S: content,\n        },\n        additional_kwargs: isAdditionalKwargs\n          ? { S: JSON.stringify(additional_kwargs) }\n          : { S: \"{}\" },\n      },\n    };\n\n    if (role) {\n      dynamoSerializedMessage.M.role = { S: role };\n    }\n\n    return dynamoSerializedMessage;\n  }\n\n  constructor({\n    tableName,\n    sessionId,\n    partitionKey,\n    sortKey,\n    messageAttributeName,\n    config,\n    key = {},\n  }: DynamoDBChatMessageHistoryFields) {\n    super();\n\n    this.tableName = tableName;\n    this.sessionId = sessionId;\n    this.client = new DynamoDBClient(config ?? {});\n    this.partitionKey = partitionKey ?? this.partitionKey;\n    this.sortKey = sortKey;\n    this.messageAttributeName =\n      messageAttributeName ?? this.messageAttributeName;\n    this.dynamoKey = key;\n\n    // override dynamoKey with partition key and sort key when key not specified\n    if (Object.keys(this.dynamoKey).length === 0) {\n      this.dynamoKey[this.partitionKey] = { S: this.sessionId };\n      if (this.sortKey) {\n        this.dynamoKey[this.sortKey] = { S: this.sortKey };\n      }\n    }\n  }\n\n  /**\n   * Retrieves all messages from the DynamoDB table and returns them as an\n   * array of `BaseMessage` instances.\n   * @returns Array of stored messages\n   */\n  async getMessages(): Promise<BaseMessage[]> {\n    try {\n      const params: GetItemCommandInput = {\n        TableName: this.tableName,\n        Key: this.dynamoKey,\n      };\n\n      const response = await this.client.send(new GetItemCommand(params));\n      const items = response.Item\n        ? (response.Item[this.messageAttributeName]?.L ?? [])\n        : [];\n      const messages = items\n        .filter(\n          (\n            item\n          ): item is AttributeValue & { M: DynamoDBSerializedChatMessage } =>\n            item.M !== undefined\n        )\n        .map((item) => {\n          const data: {\n            role?: string;\n            content: string | undefined;\n            additional_kwargs?: Record<string, unknown>;\n          } = {\n            role: item.M?.role?.S,\n            content: item.M?.text.S,\n            additional_kwargs: item.M?.additional_kwargs?.S\n              ? JSON.parse(item.M?.additional_kwargs.S)\n              : undefined,\n          };\n\n          return {\n            type: item.M?.type.S,\n            data,\n          };\n        })\n        .filter(\n          (x): x is StoredMessage =>\n            x.type !== undefined && x.data.content !== undefined\n        );\n      return mapStoredMessagesToChatMessages(messages);\n      // oxlint-disable-next-line typescript/no-explicit-any\n    } catch (error: any) {\n      throw new Error(`Error getting messages: ${error.message}`);\n    }\n  }\n\n  /**\n   * Adds a new message to the DynamoDB table.\n   * @param message The message to be added to the DynamoDB table.\n   */\n  async addMessage(message: BaseMessage) {\n    try {\n      const messages = mapChatMessagesToStoredMessages([message]);\n\n      const params: UpdateItemCommandInput = {\n        TableName: this.tableName,\n        Key: this.dynamoKey,\n        ExpressionAttributeNames: {\n          \"#m\": this.messageAttributeName,\n        },\n        ExpressionAttributeValues: {\n          \":empty_list\": {\n            L: [],\n          },\n          \":m\": {\n            L: messages.map(this.createDynamoDBSerializedChatMessage),\n          },\n        },\n        UpdateExpression:\n          \"SET #m = list_append(if_not_exists(#m, :empty_list), :m)\",\n      };\n      await this.client.send(new UpdateItemCommand(params));\n      // oxlint-disable-next-line typescript/no-explicit-any\n    } catch (error: any) {\n      throw new Error(`Error adding message: ${error.message}`);\n    }\n  }\n\n  /**\n   * Adds new messages to the DynamoDB table.\n   * @param messages The messages to be added to the DynamoDB table.\n   */\n  async addMessages(messages: BaseMessage[]): Promise<void> {\n    try {\n      const storedMessages = mapChatMessagesToStoredMessages(messages);\n      const dynamoMessages = storedMessages.map(\n        this.createDynamoDBSerializedChatMessage\n      );\n\n      const params: UpdateItemCommandInput = {\n        TableName: this.tableName,\n        Key: this.dynamoKey,\n        ExpressionAttributeNames: {\n          \"#m\": this.messageAttributeName,\n        },\n        ExpressionAttributeValues: {\n          \":empty_list\": {\n            L: [],\n          },\n          \":m\": {\n            L: dynamoMessages,\n          },\n        },\n        UpdateExpression:\n          \"SET #m = list_append(if_not_exists(#m, :empty_list), :m)\",\n      };\n      await this.client.send(new UpdateItemCommand(params));\n      // oxlint-disable-next-line typescript/no-explicit-any\n    } catch (error: any) {\n      throw new Error(`Error adding messages: ${error.message}`);\n    }\n  }\n\n  /**\n   * Deletes all messages from the DynamoDB table.\n   */\n  async clear(): Promise<void> {\n    try {\n      const params: DeleteItemCommandInput = {\n        TableName: this.tableName,\n        Key: this.dynamoKey,\n      };\n      await this.client.send(new DeleteItemCommand(params));\n      // oxlint-disable-next-line typescript/no-explicit-any\n    } catch (error: any) {\n      throw new Error(`Error clearing messages: ${error.message}`);\n    }\n  }\n}\n"],"mappings":"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"}