diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7a1e697..2d576490 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,15 +43,6 @@ repos: --follow-imports=skip, --explicit-package-bases, ] - # - repo: https://github.com/numpy/numpydoc - # rev: v1.6.0 - # hooks: - # - id: numpydoc-validation - - repo: https://github.com/psf/black - rev: 23.3.0 - hooks: - - id: black - args: [ --line-length=79 ] - repo: https://github.com/PyCQA/flake8 rev: 6.1.0 hooks: diff --git a/LICENSE b/LICENSE index 7609ced3..e1dea3fe 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Alibaba + Copyright 2024 Alibaba Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -200,192 +199,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - - --------------------------------------------------------------------------------- - - -Some codes of tests/run.py is modified from -https://github.com/alibaba/FederatedScope/blob/master/tests/run.py, which is -also licensed under the terms of the Apache 2.0. - - --------------------------------------------------------------------------------- - -Code in src/memoryscope/web/static/js/socket.io.js is adapted from -https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js (MIT License) - -Copyright (c) 2014-2021 Guillermo Rauch - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------------------------------------- - -Code in src/memoryscope/web/static/js/jquery-3.3.1.min.js is adapted from -https://code.jquery.com/jquery-3.3.1.min.js (MIT License) - -Copyright (c) JS Foundation and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------------------------------------- - -Code in src/memoryscope/web/static/js/bootstrap.bundle.min.js is adapted from -https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.bundle.min.js - (MIT License) - -Copyright (c) 2011-2019 The Bootstrap Authors (https://github -.com/twbs/bootstrap/graphs/contributors) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------------------------------------- - -Code in src/memoryscope/web/static/js/bootstrap-table.min.js is adapted from -https://unpkg.com/bootstrap-table@1.18.0/dist/bootstrap-table.min.js (MIT -License) - -Copyright (c) wenzhixin (http://wenzhixin.net.cn/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - --------------------------------------------------------------------------------- - -Code in src/memoryscope/web/static/css/bootstrap.min.css is adapted from -https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css (MIT -License) - -Copyright 2011-2019 The Bootstrap Authors -Copyright 2011-2019 Twitter, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - --------------------------------------------------------------------------------- - -Fonts in src/memoryscope/web/static/fonts/KRYPTON.ttf is adapted from -https://github.com/githubnext/monaspace (SIL Open Font License 1.1). These -fonts are distributed with their original license. See https://github -.com/githubnext/monaspace/blob/main/LICENSE for the full text of the license. -The following font families are included: - -- Monaspace (with subfamilies: Krypton) - -Copyright (c) 2023, GitHub https://github.com/githubnext/monaspace -with Reserved Font Name "Monaspace", including subfamilies: "Argon", "Neon", -"Xenon", "Radon", and "Krypton" - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - --------------------------------------------------------------------------------- - -Fonts in src/memoryscope/web/static/fonts/OSWALD.ttf is adapted from -https://fonts.google.com/specimen/Oswald (SIL Open Font License 1.1). These -fonts are distributed with their original license. See https://github -.com/googlefonts/OswaldFont/blob/main/OFL.txt for the full text of the license. - -Copyright 2016 The Oswald Project Authors (https://github -.com/googlefonts/OswaldFont) - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - --------------------------------------------------------------------------------- \ No newline at end of file diff --git a/memory_scope/memory/worker/base_worker.py b/memory_scope/memory/worker/base_worker.py index 6abf5ddf..07eeb7d7 100644 --- a/memory_scope/memory/worker/base_worker.py +++ b/memory_scope/memory/worker/base_worker.py @@ -8,6 +8,10 @@ from memory_scope.utils.timer import Timer class BaseWorker(metaclass=ABCMeta): + """ + BaseWorker is an abstract class that defines a worker with common functionalities + for managing tasks and context in both asynchronous and multi-thread environments. + """ def __init__(self, name: str, @@ -17,6 +21,18 @@ class BaseWorker(metaclass=ABCMeta): is_multi_thread: bool = False, thread_pool: ThreadPoolExecutor = None, **kwargs): + """ + Initializes the BaseWorker with the provided parameters. + + Args: + name (str): The name of the worker. + context (Dict[str, Any]): Shared context dictionary. + context_lock (optional): Lock for synchronizing access to the context in multithread mode. + raise_exception (bool, optional): Flag to control whether exceptions should be raised. + is_multi_thread (bool, optional): Flag indicating if the worker operates in multithread mode. + thread_pool (ThreadPoolExecutor, optional): Thread pool executor for managing multithread tasks. + kwargs: Additional keyword arguments. + """ self.name: str = name self.context: Dict[str, Any] = context @@ -34,18 +50,50 @@ class BaseWorker(metaclass=ABCMeta): self._parse_params(**kwargs) def _parse_params(self, **kwargs): + """ + Placeholder method for parsing additional parameters. + + Args: + kwargs: Additional keyword arguments. + """ pass def submit_async_task(self, fn, *args, **kwargs): + """ + Submits an asynchronous task to the worker. + + Args: + fn (callable): The function to be executed. + args: Positional arguments for the function. + kwargs: Keyword arguments for the function. + + Raises: + RuntimeError: If called in multithread mode. + """ if self.is_multi_thread: raise RuntimeError(f"async_task is not allowed in multi_thread condition") self.async_task_list.append((fn, args, kwargs)) async def _async_gather(self): + """ + Gathers results of all submitted asynchronous tasks. + + Returns: + A list of results from the asynchronous tasks. + """ return await asyncio.gather(*[fn(*args, **kwargs) for fn, args, kwargs in self.async_task_list]) def gather_async_result(self): + """ + Executes all asynchronous tasks and gathers their results. + + Returns: + A list of results from the asynchronous tasks. + + Raises: + RuntimeError: If called in multithread mode. + """ if self.is_multi_thread: raise RuntimeError(f"async_task is not allowed in multi_thread condition") @@ -54,18 +102,43 @@ class BaseWorker(metaclass=ABCMeta): return results def submit_thread_task(self, fn, *args, **kwargs): + """ + Submits a task to be executed in a separate thread. + + Args: + fn (callable): The function to be executed. + args: Positional arguments for the function. + kwargs: Keyword arguments for the function. + """ self.thread_task_list.append(self.thread_pool.submit(fn, *args, **kwargs)) def gather_thread_result(self): + """ + Gathers results of all submitted multithread tasks. + + Yields: + The result of each completed task. + """ for future in as_completed(self.thread_task_list): yield future.result() self.thread_task_list.clear() @abstractmethod def _run(self): + """ + Abstract method representing the main run logic of the worker that needs to be implemented by subclasses. + + Raises: + NotImplementedError: If the method is not implemented by the subclass. + """ raise NotImplementedError def run(self): + """ + Executes the worker's main logic and manages execution flow and exception handling. + + Uses a Timer to log the execution time of the worker. + """ with Timer(f"worker.{self.name}", time_log_type="wrap"): self.continue_run = True self.async_task_list.clear() @@ -80,9 +153,26 @@ class BaseWorker(metaclass=ABCMeta): self.logger.exception(f"run {self.name} failed! args={e.args}") def get_context(self, key: str, default=None): + """ + Retrieves a value from the shared context. + + Args: + key (str): The key for the context value. + default (optional): Default value if the key is not found. + + Returns: + The value from the context or the default value. + """ return self.context.get(key, default) def set_context(self, key: str, value: Any): + """ + Sets a value in the shared context. + + Args: + key (str): The key for the context value. + value (Any): The value to be set. + """ if self.is_multi_thread: with self.context_lock: self.context[key] = value @@ -90,4 +180,13 @@ class BaseWorker(metaclass=ABCMeta): self.context[key] = value def has_content(self, key: str): + """ + Checks if the context contains a specific key. + + Args: + key (str): The key to check in the context. + + Returns: + bool: True if the key is in the context, otherwise False. + """ return key in self.context diff --git a/memory_scope/memory/worker/summary/long_contra_repeat_worker.py b/memory_scope/memory/worker/summary/long_contra_repeat_worker.py index 9fc2d843..ca46bf5c 100644 --- a/memory_scope/memory/worker/summary/long_contra_repeat_worker.py +++ b/memory_scope/memory/worker/summary/long_contra_repeat_worker.py @@ -54,12 +54,12 @@ class LongContraRepeatWorker(MemoryBaseWorker): def _run(self): """ Executes the primary routine of the LongContraRepeatWorker. This involves: - 1. Retrieving not updated memory nodes. - 2. Gathering similar content for these nodes. - 3. Organizing observed nodes and generating a prompt for the language model. - 4. Calling the language model to process the prompt and receive a response. - 5. Parsing the model's response to update memory node statuses. - 6. Saving the modified memory nodes. + 1. Retrieve not updated memory nodes. + 2. Gather similar content for these nodes. + 3. Organize observed nodes and generating a prompt for the language model. + 4. Call the language model to judge the contradictions or redundancies in retrieved memories. + 5. Parse the model's response to update memory node statuses. + 6. Save the modified memory nodes. The process helps in maintaining conversation coherence by resolving contradictions and redundancies. """ diff --git a/memory_scope/memory/worker/summary/update_insight_worker.py b/memory_scope/memory/worker/summary/update_insight_worker.py index 71878b5e..995a4020 100644 --- a/memory_scope/memory/worker/summary/update_insight_worker.py +++ b/memory_scope/memory/worker/summary/update_insight_worker.py @@ -13,7 +13,7 @@ from memory_scope.utils.tool_functions import prompt_to_msg class UpdateInsightWorker(MemoryBaseWorker): """ - This class is responsible for updating insights in a memory system. It filters insight nodes + This class is responsible for updating insight value in a memory system. It filters insight nodes based on their association with observed nodes, utilizes a ranking model to prioritize them, generates refreshed insights via an LLM, and manages node statuses and content updates, incorporating features for concurrent execution and logging. @@ -80,6 +80,16 @@ class UpdateInsightWorker(MemoryBaseWorker): return insight_node, filtered_nodes, max_score def update_insight_node(self, insight_node: MemoryNode, insight_value: str): + """ + Updates the MemoryNode with the new insight value. + + Args: + insight_node (MemoryNode): The MemoryNode whose insight value needs to be updated. + insight_value (str): The new insight value. + + Returns: + MemoryNode: The updated MemoryNode with potentially revised insight value. + """ dt_handler = DatetimeHandler() key = self.prompt_handler.insight_string_format.format(name=self.target_name, key=insight_node.key) content = f"{key}{self.get_language_value(COLON_WORD)} {insight_value}" @@ -156,12 +166,13 @@ class UpdateInsightWorker(MemoryBaseWorker): it updates the status of processed nodes and gathers the results from all threads. Steps include: - 1. Retrieve lists of insight, not updated, and not reflected nodes from memory. - 2. Filter and process active insight nodes with respective not updated nodes. - 3. Sort processed results by score and select the top N. - 4. Submit tasks to update insights for the selected nodes. - 5. Gather the results of all update tasks. - 6. Mark processed nodes as updated in memory. + 1. Get lists of insight node. + 2. Get not updated, and not reflected observation nodes from memory. + 3. Filter and process active insight nodes with respective not updated observation nodes. + 4. Sort processed results by score and select the top N. + 5. Submit tasks to update insight value for the selected nodes. + 6. Gather the results of all update tasks. + 7. Mark processed nodes as updated in memory. """ insight_nodes: List[MemoryNode] = self.memory_handler.get_memories(INSIGHT_NODES) not_updated_nodes: List[MemoryNode] = self.memory_handler.get_memories(NOT_UPDATED_NODES) diff --git a/memory_scope/memory/worker/write/get_observation_with_time_worker.py b/memory_scope/memory/worker/write/get_observation_with_time_worker.py index 86083a57..83e45eff 100644 --- a/memory_scope/memory/worker/write/get_observation_with_time_worker.py +++ b/memory_scope/memory/worker/write/get_observation_with_time_worker.py @@ -32,11 +32,12 @@ class GetObservationWithTimeWorker(GetObservationWorker): def build_message(self, filter_messages: List[Message]) -> List[Message]: """ - Constructs a message for obtaining observations with timestamps based on filtered chat messages. + Constructs a prompt message for obtaining observations with timestamp information + based on filtered chat messages. - This method processes each filtered message to append a timestamp formatted per the specified format. - It then organizes these timestamped queries into a structured prompt that includes a system prompt, - few-shot examples, and the concatenated user queries, tailored to a target individual with a given language setting. + This method processes each filtered message with the timestamp information. + It then organizes these timestamped messages into a structured prompt that includes a system prompt, + few-shot examples, and the concatenated user queries. Args: filter_messages (List[Message]): A list of Message objects that have been filtered for processing. diff --git a/memory_scope/memory/worker/write/get_observation_worker.py b/memory_scope/memory/worker/write/get_observation_worker.py index e3106d04..6ff801ae 100644 --- a/memory_scope/memory/worker/write/get_observation_worker.py +++ b/memory_scope/memory/worker/write/get_observation_worker.py @@ -13,6 +13,9 @@ from memory_scope.utils.tool_functions import prompt_to_msg class GetObservationWorker(MemoryBaseWorker): + """ + A specialized worker class to generate the observations from the original chat histories. + """ FILE_PATH: str = __file__ OBS_STORE_KEY: str = NEW_OBS_NODES @@ -20,6 +23,18 @@ class GetObservationWorker(MemoryBaseWorker): self.generation_model_kwargs: dict = kwargs.get("generation_model_kwargs", {}) def add_observation(self, message: Message, time_infer: str, obs_content: str, keywords: str): + """ + Builds a MemoryNode containing the observation details. + + Args: + message (Message): The source message from which the observation is derived. + time_infer (str): The inferred time if available. + obs_content (str): The content of the observation. + keywords (str): Keywords associated with the observation. + + Returns: + MemoryNode: The constructed MemoryNode containing the observation. + """ dt_handler = DatetimeHandler(dt=message.time_created) # buidl meta data @@ -45,6 +60,12 @@ class GetObservationWorker(MemoryBaseWorker): timestamp=message.time_created) def filter_messages(self) -> List[Message]: + """ + Filters the chat messages to only include those which not contain time-related keywords. + + Returns: + List[Message]: A list of filtered messages that mention time. + """ filter_messages = [] for msg in self.chat_messages: if not DatetimeHandler.has_time_word(query=msg.content): @@ -95,7 +116,7 @@ class GetObservationWorker(MemoryBaseWorker): and stores the extracted information as MemoryNode objects within the conversation memory. Steps: - 1. Filters messages based on predefined criteria. + 1. Filter messages based on predefined criteria. 2. Constructs a message for the language model to generate observations. 3. Calls the language model to predict observation details. 4. Parses the model's response to extract observation lists. diff --git a/memory_scope/memory/worker/write/info_filter_worker.py b/memory_scope/memory/worker/write/info_filter_worker.py index 7146ea55..d3ebcc34 100644 --- a/memory_scope/memory/worker/write/info_filter_worker.py +++ b/memory_scope/memory/worker/write/info_filter_worker.py @@ -24,8 +24,8 @@ class InfoFilterWorker(MemoryBaseWorker): def _run(self): """ - Filters user messages in the chat, generates a prompt incorporating these messages, - utilizes an LLM to process the prompt, parses the LLM's response to score each message, + Filters user messages in the chat, generates a prompt incorporating these messages, + utilizes an LLM to rate the information score for each message, and updates `self.chat_messages` to only include messages with designated scores. This method executes the following steps: @@ -33,7 +33,7 @@ class InfoFilterWorker(MemoryBaseWorker): 2. Constructs a prompt with user messages for LLM input. 3. Calls the LLM model with the constructed prompt. 4. Parses the LLM's response to extract message scores. - 5. Retains messages in `self.chat_messages` based on their scores. + 5. Retains message in `self.chat_messages` based on their scores. """ # filter user msg info_messages: List[Message] = [] diff --git a/memory_scope/memory/worker/write/load_memory_worker.py b/memory_scope/memory/worker/write/load_memory_worker.py index 26ed12d9..7d39943e 100644 --- a/memory_scope/memory/worker/write/load_memory_worker.py +++ b/memory_scope/memory/worker/write/load_memory_worker.py @@ -18,6 +18,12 @@ class LoadMemoryWorker(MemoryBaseWorker): @timer def retrieve_not_reflected_memory(self, query: str): + """ + Retrieves top-K not reflected memories based on the query and stores them in the memory handler. + + Args: + query (str): The search query for retrieving memories. + """ if not self.retrieve_not_reflected_top_k: return @@ -35,6 +41,12 @@ class LoadMemoryWorker(MemoryBaseWorker): @timer def retrieve_not_updated_memory(self, query: str): + """ + Retrieves top-K not updated memories based on the query and stores them in the memory handler. + + Args: + query (str): The search query for retrieving memories. + """ if not self.retrieve_not_updated_top_k: return @@ -52,6 +64,12 @@ class LoadMemoryWorker(MemoryBaseWorker): @timer def retrieve_insight_memory(self, query: str): + """ + Retrieves top-K insight memories based on the query and stores them in the memory handler. + + Args: + query (str): The search query for retrieving memories. + """ if not self.retrieve_insight_top_k: return @@ -68,6 +86,13 @@ class LoadMemoryWorker(MemoryBaseWorker): @timer def retrieve_today_memory(self, query: str, dt: str): + """ + Retrieves top-K memories from today based on the query and stores them in the memory handler. + + Args: + query (str): The search query for retrieving memories. + dt (str): The date string to filter today's memories. + """ if not self.retrieve_today_top_k: return @@ -86,7 +111,7 @@ class LoadMemoryWorker(MemoryBaseWorker): def _run(self): """ - Initiates asynchronous tasks to retrieve various types of memory data including + Initiates multithread tasks to retrieve various types of memory data including not reflected, not updated, insights, and data from today. After submitting all tasks, it waits for their completion by calling `gather_thread_result`. diff --git a/memory_scope/memory/worker/write/update_memory_worker.py b/memory_scope/memory/worker/write/update_memory_worker.py index e394d92c..4c8a8fba 100644 --- a/memory_scope/memory/worker/write/update_memory_worker.py +++ b/memory_scope/memory/worker/write/update_memory_worker.py @@ -14,6 +14,12 @@ class UpdateMemoryWorker(MemoryBaseWorker): self.memory_key: str = kwargs.get("memory_key", "") def from_query(self): + """ + Creates a MemoryNode from the provided query if present in chat_kwargs. + + Returns: + List[MemoryNode]: A list containing a single MemoryNode created from the query. + """ if "query" not in self.chat_kwargs: return @@ -31,12 +37,24 @@ class UpdateMemoryWorker(MemoryBaseWorker): return [node] def from_memory_key(self): + """ + Retrieves memories based on the memory key if it exists. + + Returns: + List[MemoryNode]: A list of MemoryNode objects retrieved using the memory key. + """ if not self.memory_key: return return self.memory_handler.get_memories(keys=self.memory_key) def delete_all(self): + """ + Marks all memories for deletion by setting their action_status to 'DELETE'. + + Returns: + List[MemoryNode]: A list of all MemoryNode objects marked for deletion. + """ nodes: List[MemoryNode] = self.memory_handler.get_memories(keys="all") for node in nodes: node.action_status = ActionStatusEnum.DELETE.value @@ -44,6 +62,12 @@ class UpdateMemoryWorker(MemoryBaseWorker): return nodes def delete_memory(self): + """ + Marks specific memories for deletion based on query or memory_id present in chat_kwargs. + + Returns: + List[MemoryNode]: A list of MemoryNode objects marked for deletion based on the query or memory_id. + """ if "query" in self.chat_kwargs: query = self.chat_kwargs["query"].strip() if not query: @@ -75,6 +99,12 @@ class UpdateMemoryWorker(MemoryBaseWorker): return [] def _run(self): + """ + Executes a memory update method provided via the 'method' attribute. + + The method specified by the 'method' attribute is invoked, + which updates memories accordingly. + """ method = self.method.strip() if not hasattr(self, method): self.logger.info(f"method={method} is missing!")