From 2285f0566ed214fd4cc4636f4da258b138931258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sun, 3 Sep 2023 19:38:01 +0800 Subject: [PATCH 01/30] refactor: prompt --- metagpt/actions/talk_action.py | 53 ++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index 4eed0d4f8..12b9da030 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -27,22 +27,16 @@ class TalkAction(Action): @property def prompt(self): - prompt = "" - if CONFIG.agent_description: - prompt = ( - f"You are {CONFIG.agent_description}. Your responses should align with the role-play agreement, " - f"maintaining the character's persona and habits. When faced with unrelated questions, playfully " - f"decline to answer without revealing your AI nature to preserve the character's image.\n\n" - ) - prompt += f"Background knowledge:\n{self._knowledge}\n\n" if self._knowledge else "" - prompt += f"{self._history_summary}\n\n" - if self._history_summary != "": - prompt += "According to the historical conversation above, " - language = CONFIG.language or DEFAULT_LANGUAGE - prompt += ( - f"Answer the following questions in {language}, and the answers must follow the Markdown format.\n " - f"{self._talk}" - ) + kvs = { + "{role}": CONFIG.agent_description or "", + "{history}": self._history_summary or "", + "{knowledge}": self._knowledge or "", + "{language}": CONFIG.language or DEFAULT_LANGUAGE, + "{ask}": self._talk, + } + prompt = TalkAction.__FORMATION__ + for k, v in kvs.items(): + prompt = prompt.replace(k, v) return prompt async def run(self, *args, **kwargs) -> ActionOutput: @@ -52,3 +46,30 @@ class TalkAction(Action): logger.info(rsp) self._rsp = ActionOutput(content=rsp) return self._rsp + + __FORMATION__ = """Formation: "Capacity and role" defines the role you are currently playing; + "[HISTORY_BEGIN]" and "[HISTORY_END]" tags enclose the historical conversation; + "[KNOWLEDGE_BEGIN]" and "[KNOWLEDGE_END]" tags enclose the knowledge may help for your responses; + "Statement" defines the work detail you need to complete at this stage; + "[ASK_BEGIN]" and [ASK_END] tags enclose the requirements for your to respond; + "Constraint" defines the conditions that your responses must comply with. + +Capacity and role: {role} +Statement: Your responses should align with the role-play agreement, maintaining the + character's persona and habits. When faced with unrelated questions, playfully decline to answer without revealing + your AI nature to preserve the character's image. Statement: the answers must follow the Markdown format. + +[HISTORY_BEGIN] +{history} +[HISTORY_END] + +[KNOWLEDGE_BEGIN] +{knowledge} +[KNOWLEDGE_END] + +Statement: According to the historical conversation and knowledge above if helpful, Answer the following questions in + {language}, and the answers must follow the Markdown format. + + [ASK_BEGIN] + {ask} + [ASK_END]""" From d6ffa4906f71205ec4a358152eb1ba81fffe60f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sun, 3 Sep 2023 19:55:53 +0800 Subject: [PATCH 02/30] refactor: prompt --- metagpt/actions/talk_action.py | 39 ++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index 12b9da030..fead3c8b9 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -34,7 +34,7 @@ class TalkAction(Action): "{language}": CONFIG.language or DEFAULT_LANGUAGE, "{ask}": self._talk, } - prompt = TalkAction.__FORMATION__ + prompt = TalkAction.__FORMATION_LOOSE__ for k, v in kvs.items(): prompt = prompt.replace(k, v) return prompt @@ -57,7 +57,34 @@ class TalkAction(Action): Capacity and role: {role} Statement: Your responses should align with the role-play agreement, maintaining the character's persona and habits. When faced with unrelated questions, playfully decline to answer without revealing - your AI nature to preserve the character's image. Statement: the answers must follow the Markdown format. + your AI nature to preserve the character's image. + +[HISTORY_BEGIN] +{history} +[HISTORY_END] + +[KNOWLEDGE_BEGIN] +{knowledge} +[KNOWLEDGE_END] + +Statement: According to the historical conversation and knowledge above if helpful, Answer the following questions in +{language}, and the answers must follow the Markdown format, excluding any tag likes "[HISTORY_BEGIN]", +"[HISTORY_END]", "[KNOWLEDGE_BEGIN]", "[KNOWLEDGE_END]", "[ASK_BEGIN]", "[ASK_END]" + +[ASK_BEGIN] +{ask} +[ASK_END]""" + + __FORMATION_LOOSE__ = """Formation: "Capacity and role" defines the role you are currently playing; + "[HISTORY_BEGIN]" and "[HISTORY_END]" tags enclose the historical conversation; + "[KNOWLEDGE_BEGIN]" and "[KNOWLEDGE_END]" tags enclose the knowledge may help for your responses; + "Statement" defines the work detail you need to complete at this stage; + "[ASK_BEGIN]" and [ASK_END] tags enclose the requirements for your to respond; + "Constraint" defines the conditions that your responses must comply with. + +Capacity and role: {role} +Statement: Your responses should maintaining the character's persona and habits. When faced with unrelated questions +, playfully decline to answer without revealing your AI nature to preserve the character's image. [HISTORY_BEGIN] {history} @@ -69,7 +96,7 @@ Statement: Your responses should align with the role-play agreement, maintaining Statement: According to the historical conversation and knowledge above if helpful, Answer the following questions in {language}, and the answers must follow the Markdown format. - - [ASK_BEGIN] - {ask} - [ASK_END]""" + +[ASK_BEGIN] +{ask} +[ASK_END]""" From b5c149f22507ffe139ca9333c50934af16a36611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Sun, 3 Sep 2023 20:02:24 +0800 Subject: [PATCH 03/30] refactor: prompt --- metagpt/actions/talk_action.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index fead3c8b9..2a04fb9c8 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -67,9 +67,10 @@ Statement: Your responses should align with the role-play agreement, maintaining {knowledge} [KNOWLEDGE_END] -Statement: According to the historical conversation and knowledge above if helpful, Answer the following questions in -{language}, and the answers must follow the Markdown format, excluding any tag likes "[HISTORY_BEGIN]", -"[HISTORY_END]", "[KNOWLEDGE_BEGIN]", "[KNOWLEDGE_END]", "[ASK_BEGIN]", "[ASK_END]" +Statement: If the information is insufficient, you can search in the historical conversation or knowledge. +Statement: Answer the following questions in {language}, and the answers must follow the Markdown format + , excluding any tag likes "[HISTORY_BEGIN]", "[HISTORY_END]", "[KNOWLEDGE_BEGIN]", "[KNOWLEDGE_END]", "[ASK_BEGIN]" + , "[ASK_END]" [ASK_BEGIN] {ask} @@ -94,8 +95,10 @@ Statement: Your responses should maintaining the character's persona and habits. {knowledge} [KNOWLEDGE_END] -Statement: According to the historical conversation and knowledge above if helpful, Answer the following questions in - {language}, and the answers must follow the Markdown format. +Statement: If the information is insufficient, you can search in the historical conversation or knowledge. +Statement: Answer the following questions in {language}, and the answers must follow the Markdown format + , excluding any tag likes "[HISTORY_BEGIN]", "[HISTORY_END]", "[KNOWLEDGE_BEGIN]", "[KNOWLEDGE_END]", "[ASK_BEGIN]" + , "[ASK_END]" [ASK_BEGIN] {ask} From e06aa62ac4dcd5ed4ec401f16ae34ecd4f178034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 10:11:19 +0800 Subject: [PATCH 04/30] refactor: prompt --- metagpt/actions/talk_action.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index 2a04fb9c8..526d921f8 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -27,6 +27,26 @@ class TalkAction(Action): @property def prompt(self): + prompt = "" + if CONFIG.agent_description: + prompt = ( + f"You are {CONFIG.agent_description}. Your responses should align with the role-play agreement, " + f"maintaining the character's persona and habits. When faced with unrelated questions, playfully " + f"decline to answer without revealing your AI nature to preserve the character's image.\n\n" + ) + prompt += f"Background knowledge:\n{self._knowledge}\n\n" if self._knowledge else "" + prompt += f"{self._history_summary}\n\n" + if self._history_summary != "": + prompt += "According to the historical conversation above, " + language = CONFIG.language or DEFAULT_LANGUAGE + prompt += ( + f"Answer the following questions in {language}, and the answers must follow the Markdown format.\n " + f"{self._talk}" + ) + return prompt + + @property + def prompt_new(self): kvs = { "{role}": CONFIG.agent_description or "", "{history}": self._history_summary or "", From 63594cd8fd924ca3aff0153354fd78e5e415b507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 10:12:10 +0800 Subject: [PATCH 05/30] refactor: prompt --- metagpt/actions/talk_action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index 526d921f8..83504b62d 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -46,7 +46,7 @@ class TalkAction(Action): return prompt @property - def prompt_new(self): + def formation_prompt(self): kvs = { "{role}": CONFIG.agent_description or "", "{history}": self._history_summary or "", From 2f95a8a2000aee5e1aa07a29259a81cdd0c800f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 11:42:14 +0800 Subject: [PATCH 06/30] feat: +config --- config/config.yaml | 9 ++++++++- metagpt/utils/redis.py | 0 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 metagpt/utils/redis.py diff --git a/config/config.yaml b/config/config.yaml index 7c3d212f6..765a74b8a 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -83,4 +83,11 @@ MODEL_FOR_RESEARCHER_REPORT: gpt-3.5-turbo-16k S3: access_key: "YOUR_S3_ACCESS_KEY" secret_key: "YOUR_S3_SECRET_KEY" - endpoint_url: "YOUR_S3_ENDPOINT_URL" \ No newline at end of file + endpoint_url: "YOUR_S3_ENDPOINT_URL" + +### Redis config +REDIS: + host: "YOUR_REDIS_HOST" + port: YOUR_REDIS_PORT, int + password: "YOUR_REDIS_PASSWORD" + db: YOUR_REDIS_DB_INDEX, int \ No newline at end of file diff --git a/metagpt/utils/redis.py b/metagpt/utils/redis.py new file mode 100644 index 000000000..e69de29bb From 96f833cf8fafcea3555efd5871bea2ed2364647f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 12:47:45 +0800 Subject: [PATCH 07/30] feat: +redis --- metagpt/memory/brain_memory.py | 34 ++++-- metagpt/utils/redis.py | 198 +++++++++++++++++++++++++++++++++ requirements.txt | 3 +- 3 files changed, 222 insertions(+), 13 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index a5a3dbfc7..275cd14df 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -6,7 +6,7 @@ @File : brain_memory.py @Desc : Support memory for multiple tasks and multiple mainlines. """ - +import hashlib from enum import Enum from typing import Dict, List @@ -28,6 +28,10 @@ class BrainMemory(pydantic.BaseModel): stack: List[Dict] = [] solution: List[Dict] = [] knowledge: List[Dict] = [] + # If the fingerprint of the history text is found in the `historical_summary_fingerprint`, + # it indicates that the text has already been incorporated into the `history summary`. + historical_summary_fingerprint: List[str] = [] + historical_summary: str = "" def add_talk(self, msg: Message): msg.add_tag(MessageType.Talk.value) @@ -58,17 +62,19 @@ class BrainMemory(pydantic.BaseModel): return "\n".join(texts) def move_to_solution(self, history_summary): - """放入solution队列,以备后续长程检索。目前还未加此功能,先用history_summary顶替""" - if len(self.history) < 2: - return - msgs = self.history[:-1] - self.solution.extend(msgs) - if not Message(**self.history[-1]).is_contain(MessageType.Talk.value): - self.solution.append(self.history[-1]) - self.history = [] - else: - self.history = self.history[-1:] - self.history.insert(0, Message(content="RESOLVED: " + history_summary)) + """Put it in the solution queue for future long-term retrieval. + This functionality hasn't been added yet, so use the history summary as a temporary substitute for now.""" + pass + # if len(self.history) < 2: + # return + # msgs = self.history[:-1] + # self.solution.extend(msgs) + # if not Message(**self.history[-1]).is_contain(MessageType.Talk.value): + # self.solution.append(self.history[-1]) + # self.history = [] + # else: + # self.history = self.history[-1:] + # self.history.insert(0, Message(content="RESOLVED: " + history_summary)) @property def last_talk(self): @@ -78,3 +84,7 @@ class BrainMemory(pydantic.BaseModel): if not last_msg.is_contain(MessageType.Talk.value): return None return last_msg.content + + @staticmethod + def get_md5(text: str) -> str: + return hashlib.md5(text.encode()).hexdigest() diff --git a/metagpt/utils/redis.py b/metagpt/utils/redis.py index e69de29bb..f2ae3222a 100644 --- a/metagpt/utils/redis.py +++ b/metagpt/utils/redis.py @@ -0,0 +1,198 @@ +# !/usr/bin/python3 +# -*- coding: utf-8 -*- +# @Author: Hui +# @Desc: { redis client } +# @Date: 2022/11/28 10:12 +import json +from datetime import timedelta +from enum import Enum +from typing import Awaitable, Callable, Optional, Union + +from redis import asyncio as aioredis + +from metagpt.config import CONFIG +from metagpt.logs import logger + + +class RedisTypeEnum(Enum): + """Redis 数据类型""" + + String = "String" + List = "List" + Hash = "Hash" + Set = "Set" + ZSet = "ZSet" + + +def make_url( + dialect: str, + *, + user: Optional[str] = None, + password: Optional[str] = None, + host: Optional[str] = None, + port: Optional[Union[str, int]] = None, + name: Optional[Union[str, int]] = None, +) -> str: + url_parts = [f"{dialect}://"] + if user or password: + if user: + url_parts.append(user) + if password: + url_parts.append(f":{password}") + url_parts.append("@") + + if not host and not dialect.startswith("sqlite"): + host = "127.0.0.1" + + if host: + url_parts.append(f"{host}") + if port: + url_parts.append(f":{port}") + + # 比如redis可能传入0 + if name is not None: + url_parts.append(f"/{name}") + return "".join(url_parts) + + +class RedisAsyncClient(aioredis.Redis): + """异步的客户端 + 例子:: + + rdb = RedisAsyncClient() + print(rdb.url) + + Args: + host: 服务器地址 + port: 服务器端口 + user: 用户名 + db: 数据库 + password: 密码 + decode_responses: 字符串输入被编码成utf8存储在Redis里了,而取出来的时候还是被编码后的bytes,需要显示的decode才能变成字符串 + health_check_interval: 定时检测连接,防止出现ConnectionErrors (104, Connection reset by peer) + """ + + def __init__( + self, + host: str = "localhost", + port: int = 6379, + db: int = 0, + password: str = None, + decode_responses=True, + health_check_interval=10, + socket_connect_timeout=5, + retry_on_timeout=True, + socket_keepalive=True, + **kwargs, + ): + super().__init__( + host=host, + port=port, + db=db, + password=password, + decode_responses=decode_responses, + health_check_interval=health_check_interval, + socket_connect_timeout=socket_connect_timeout, + retry_on_timeout=retry_on_timeout, + socket_keepalive=socket_keepalive, + **kwargs, + ) + self.url = make_url("redis", host=host, port=port, name=db, password=password) + + +class RedisCacheInfo(object): + """统一缓存信息类""" + + def __init__(self, key, timeout: Union[int, timedelta] = timedelta(seconds=60), data_type=RedisTypeEnum.String): + """ + 缓存信息类初始化 + Args: + key: 缓存的key + timeout: 缓存过期时间, 单位秒 + data_type: 缓存采用的数据结构 (不传并不影响,用于标记业务采用的是什么数据结构) + """ + self.key = key + self.timeout = timeout + self.data_type = data_type + + def __str__(self): + return f"cache key {self.key} timeout {self.timeout}s" + + +class RedisManager: + client: RedisAsyncClient = None + + @classmethod + def init_redis_conn(cls, host, port, password, db): + """初始化redis 连接""" + if cls.client is None: + cls.client = RedisAsyncClient(host=host, port=port, password=password, db=db) + + @classmethod + async def set_with_cache_info(cls, redis_cache_info: RedisCacheInfo, value): + """ + 根据 RedisCacheInfo 设置 Redis 缓存 + :param redis_cache_info: RedisCacheInfo缓存信息对象 + :param value: 缓存的值 + :return: + """ + await cls.client.setex(redis_cache_info.key, redis_cache_info.timeout, value) + + @classmethod + async def get_with_cache_info(cls, redis_cache_info: RedisCacheInfo): + """ + 根据 RedisCacheInfo 获取 Redis 缓存 + :param redis_cache_info: RedisCacheInfo 缓存信息对象 + :return: + """ + cache_info = await cls.client.get(redis_cache_info.key) + return cache_info + + @classmethod + async def del_with_cache_info(cls, redis_cache_info: RedisCacheInfo): + """ + 根据 RedisCacheInfo 删除 Redis 缓存 + :param redis_cache_info: RedisCacheInfo缓存信息对象 + :return: + """ + await cls.client.delete(redis_cache_info.key) + + @staticmethod + async def get_or_set_cache(cache_info: RedisCacheInfo, fetch_data_func: Callable[[], Awaitable[dict]]) -> dict: + """ + 获取缓存数据,如果缓存不存在,则从提供的函数中获取并设置缓存 + 当前版本仅支持 json 形式的 string 格式数据 + """ + + serialized_data = await RedisManager.get_with_cache_info(cache_info) + + if serialized_data: + return json.loads(serialized_data) + + data = await fetch_data_func() + try: + serialized_data = json.dumps(data) + await RedisManager.set_with_cache_info(cache_info, serialized_data) + except Exception as e: + logger.warning(f"数据 {data} 通过 json 进行序列化缓存失败:{e}") + + return data + + @classmethod + def is_valid(cls): + return cls.client is not None + + +class Redis: + def __init__(self): + self._config = CONFIG.REDIS + if not self._config: + return + try: + host = self._config["host"] + port = int(self._config["port"]) + pwd = self._config["password"] + db = int(self._config["db"]) + RedisManager.init_redis_conn(host=host, port=port, password=pwd, db=db) + except Exception as e: + logger.warning(f"Redis initialization has failed:{e}") diff --git a/requirements.txt b/requirements.txt index 5daf710c7..588b29e0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,4 +41,5 @@ qdrant-client==1.4.0 connexion[swagger-ui] aiohttp_jinja2 azure-cognitiveservices-speech==1.31.0 -aioboto3~=11.3.0 \ No newline at end of file +aioboto3~=11.3.0 +redis==4.3.5 \ No newline at end of file From 0ffd3db9473eda5e2172e8bc826638feddb987cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 13:21:29 +0800 Subject: [PATCH 08/30] feat: +redis --- metagpt/const.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metagpt/const.py b/metagpt/const.py index fbc2c928a..e9fa118d7 100644 --- a/metagpt/const.py +++ b/metagpt/const.py @@ -57,3 +57,6 @@ METAGPT_API_VERSION = "METAGPT_API_VERSION" # format BASE64_FORMAT = "base64" + +# REDIS +REDIS_KEY = "REDIS_KEY" From cce76df319ed5174d8a1aca88d498354856b741f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:03:20 +0800 Subject: [PATCH 09/30] feat: +redis --- metagpt/memory/brain_memory.py | 21 +++++++++++++++++++++ metagpt/utils/redis.py | 16 ++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 275cd14df..619a9e1f3 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -7,12 +7,14 @@ @Desc : Support memory for multiple tasks and multiple mainlines. """ import hashlib +import json from enum import Enum from typing import Dict, List import pydantic from metagpt import Message +from metagpt.utils.redis import Redis class MessageType(Enum): @@ -32,6 +34,7 @@ class BrainMemory(pydantic.BaseModel): # it indicates that the text has already been incorporated into the `history summary`. historical_summary_fingerprint: List[str] = [] historical_summary: str = "" + last_history_id: str = "" def add_talk(self, msg: Message): msg.add_tag(MessageType.Talk.value) @@ -88,3 +91,21 @@ class BrainMemory(pydantic.BaseModel): @staticmethod def get_md5(text: str) -> str: return hashlib.md5(text.encode()).hexdigest() + + @staticmethod + async def loads(redis_key: str) -> "BrainMemory": + redis = Redis() + if not redis.is_valid() or not redis_key: + return False + v = await redis.get(key=redis_key) + if not v: + data = json.loads(v) + return BrainMemory(**data) + return None + + async def dumps(self, redis_key: str, timeout_sec: int = 30 * 60): + redis = Redis() + if not redis.is_valid() or not redis_key: + return False + v = self.json() + await redis.set(key=redis_key, data=v, timeout_sec=timeout_sec) diff --git a/metagpt/utils/redis.py b/metagpt/utils/redis.py index f2ae3222a..ce9d1bc8e 100644 --- a/metagpt/utils/redis.py +++ b/metagpt/utils/redis.py @@ -196,3 +196,19 @@ class Redis: RedisManager.init_redis_conn(host=host, port=port, password=pwd, db=db) except Exception as e: logger.warning(f"Redis initialization has failed:{e}") + + def is_valid(self): + return RedisManager.is_valid() + + async def get(self, key: str) -> str: + if not self.is_valid() or not key: + return None + v = await RedisManager.get_with_cache_info(redis_cache_info=RedisCacheInfo(key=key)) + return v + + async def set(self, key: str, data: str, timeout_sec: int): + if not self.is_valid() or not key: + return + await RedisManager.set_with_cache_info( + redis_cache_info=RedisCacheInfo(key=key, timeout=timeout_sec), value=data + ) From 41e90b4f483da8d734fb7497975e499330f46e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:12:17 +0800 Subject: [PATCH 10/30] feat: +redis --- metagpt/memory/brain_memory.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 619a9e1f3..baad76562 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -96,12 +96,12 @@ class BrainMemory(pydantic.BaseModel): async def loads(redis_key: str) -> "BrainMemory": redis = Redis() if not redis.is_valid() or not redis_key: - return False + return BrainMemory() v = await redis.get(key=redis_key) if not v: data = json.loads(v) return BrainMemory(**data) - return None + return BrainMemory() async def dumps(self, redis_key: str, timeout_sec: int = 30 * 60): redis = Redis() From 26c4ed6e2245ecd19423cadc0faf697241170528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:38:35 +0800 Subject: [PATCH 11/30] feat: +code --- metagpt/memory/brain_memory.py | 8 ++++---- metagpt/utils/redis.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index baad76562..3b27c2a94 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -93,8 +93,8 @@ class BrainMemory(pydantic.BaseModel): return hashlib.md5(text.encode()).hexdigest() @staticmethod - async def loads(redis_key: str) -> "BrainMemory": - redis = Redis() + async def loads(redis_key: str, redis_conf: Dict = None) -> "BrainMemory": + redis = Redis(conf=redis_conf) if not redis.is_valid() or not redis_key: return BrainMemory() v = await redis.get(key=redis_key) @@ -103,8 +103,8 @@ class BrainMemory(pydantic.BaseModel): return BrainMemory(**data) return BrainMemory() - async def dumps(self, redis_key: str, timeout_sec: int = 30 * 60): - redis = Redis() + async def dumps(self, redis_key: str, timeout_sec: int = 30 * 60, redis_conf: Dict = None): + redis = Redis(conf=redis_conf) if not redis.is_valid() or not redis_key: return False v = self.json() diff --git a/metagpt/utils/redis.py b/metagpt/utils/redis.py index ce9d1bc8e..7d1d88fbd 100644 --- a/metagpt/utils/redis.py +++ b/metagpt/utils/redis.py @@ -6,7 +6,7 @@ import json from datetime import timedelta from enum import Enum -from typing import Awaitable, Callable, Optional, Union +from typing import Awaitable, Callable, Dict, Optional, Union from redis import asyncio as aioredis @@ -184,8 +184,8 @@ class RedisManager: class Redis: - def __init__(self): - self._config = CONFIG.REDIS + def __init__(self, conf: Dict = None): + self._config = conf or CONFIG.REDIS if not self._config: return try: From d6130c2d99361d02c7a68cf9384d7ae3660f8d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:50:54 +0800 Subject: [PATCH 12/30] feat: +to_redis_key --- metagpt/memory/brain_memory.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 3b27c2a94..faf7693ad 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -109,3 +109,7 @@ class BrainMemory(pydantic.BaseModel): return False v = self.json() await redis.set(key=redis_key, data=v, timeout_sec=timeout_sec) + + @staticmethod + def to_redis_key(prefix: str, user_id: str, chat_id: str): + return f"{prefix}:{chat_id}:{user_id}" From 0e717a0537c854b7fdd7674c4a7326898e33092f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:54:40 +0800 Subject: [PATCH 13/30] feat: +to_redis_key --- config/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yaml b/config/config.yaml index 765a74b8a..5c8dea03e 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -90,4 +90,4 @@ REDIS: host: "YOUR_REDIS_HOST" port: YOUR_REDIS_PORT, int password: "YOUR_REDIS_PASSWORD" - db: YOUR_REDIS_DB_INDEX, int \ No newline at end of file + db: "YOUR_REDIS_DB_INDEX, str, 0-based" \ No newline at end of file From 308f83c82c4442d42613d642c5080a6d07a052a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 14:55:26 +0800 Subject: [PATCH 14/30] feat: +to_redis_key --- metagpt/utils/redis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/utils/redis.py b/metagpt/utils/redis.py index 7d1d88fbd..b94eee8e2 100644 --- a/metagpt/utils/redis.py +++ b/metagpt/utils/redis.py @@ -192,7 +192,7 @@ class Redis: host = self._config["host"] port = int(self._config["port"]) pwd = self._config["password"] - db = int(self._config["db"]) + db = self._config["db"] RedisManager.init_redis_conn(host=host, port=port, password=pwd, db=db) except Exception as e: logger.warning(f"Redis initialization has failed:{e}") From 0a494171fa71b789f685c676ea6b7612c4785bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 15:30:48 +0800 Subject: [PATCH 15/30] fixbug: prerequisite --- metagpt/roles/role.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/metagpt/roles/role.py b/metagpt/roles/role.py index 2f0f713f8..b1ace19fa 100644 --- a/metagpt/roles/role.py +++ b/metagpt/roles/role.py @@ -97,8 +97,9 @@ class RoleContext(BaseModel): def prerequisite(self): """Retrieve information with `prerequisite` tag""" if self.memory and hasattr(self.memory, "get_by_tags"): - return self.memory.get_by_tags([MessageTag.Prerequisite.value]) - return "" + vv = self.memory.get_by_tags([MessageTag.Prerequisite.value]) + return vv[-1:] if len(vv) > 1 else vv + return [] class Role: From fb6bb4b69210909dbf842e83f6fd2277bb61990c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 15:39:11 +0800 Subject: [PATCH 16/30] feat: is dirty --- metagpt/memory/brain_memory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index faf7693ad..8ae7ed959 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -35,14 +35,17 @@ class BrainMemory(pydantic.BaseModel): historical_summary_fingerprint: List[str] = [] historical_summary: str = "" last_history_id: str = "" + is_dirty: bool = False def add_talk(self, msg: Message): msg.add_tag(MessageType.Talk.value) self.history.append(msg.dict()) + self.is_dirty = True def add_answer(self, msg: Message): msg.add_tag(MessageType.Answer.value) self.history.append(msg.dict()) + self.is_dirty = True def get_knowledge(self) -> str: texts = [Message(**m).content for m in self.knowledge] From 82c7fd94fd9ff500eecdc3fcbd805301178feee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 15:50:17 +0800 Subject: [PATCH 17/30] feat: is dirty --- metagpt/memory/brain_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 8ae7ed959..a925474b7 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -101,7 +101,7 @@ class BrainMemory(pydantic.BaseModel): if not redis.is_valid() or not redis_key: return BrainMemory() v = await redis.get(key=redis_key) - if not v: + if v: data = json.loads(v) return BrainMemory(**data) return BrainMemory() From 88419224586ec683db92ae83e4b4aad35bfb5d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 16:05:01 +0800 Subject: [PATCH 18/30] feat: +cache --- metagpt/memory/brain_memory.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index a925474b7..8b1b31aae 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -103,7 +103,9 @@ class BrainMemory(pydantic.BaseModel): v = await redis.get(key=redis_key) if v: data = json.loads(v) - return BrainMemory(**data) + bm = BrainMemory(**data) + bm.is_dirty = False + return bm return BrainMemory() async def dumps(self, redis_key: str, timeout_sec: int = 30 * 60, redis_conf: Dict = None): @@ -112,6 +114,7 @@ class BrainMemory(pydantic.BaseModel): return False v = self.json() await redis.set(key=redis_key, data=v, timeout_sec=timeout_sec) + self.is_dirty = False @staticmethod def to_redis_key(prefix: str, user_id: str, chat_id: str): From c4a0bd14385f529cb441c7e527baf554d2d74601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 16:40:40 +0800 Subject: [PATCH 19/30] fixbug: tags --- metagpt/schema.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/metagpt/schema.py b/metagpt/schema.py index ce08455fc..987fccef2 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -10,7 +10,7 @@ from __future__ import annotations from dataclasses import dataclass, field from enum import Enum -from typing import Type, TypedDict, Set, Optional, List +from typing import Optional, Set, Type, TypedDict from pydantic import BaseModel @@ -29,9 +29,10 @@ class RawMessage(TypedDict): @dataclass class Message: """list[: ]""" + content: str instruct_content: BaseModel = field(default=None) - role: str = field(default='user') # system / user / assistant + role: str = field(default="user") # system / user / assistant cause_by: Type["Action"] = field(default="") sent_from: str = field(default="") send_to: str = field(default="") @@ -45,10 +46,7 @@ class Message: return self.__str__() def to_dict(self) -> dict: - return { - "role": self.role, - "content": self.content - } + return {"role": self.role, "content": self.content} def add_tag(self, tag): if self.tags is None: @@ -64,7 +62,7 @@ class Message: """Determine whether the message contains tags.""" if not tags or not self.tags: return False - intersection = set(tags) & self.tags + intersection = set(tags) & set(self.tags) return len(intersection) > 0 def is_contain(self, tag): @@ -76,7 +74,7 @@ class Message: "instruct_content": self.instruct_content, "sent_from": self.sent_from, "send_to": self.send_to, - "tags": self.tags + "tags": self.tags, } m = {"content": self.content} @@ -89,39 +87,39 @@ class Message: @dataclass class UserMessage(Message): """便于支持OpenAI的消息 - Facilitate support for OpenAI messages + Facilitate support for OpenAI messages """ def __init__(self, content: str): - super().__init__(content, 'user') + super().__init__(content, "user") @dataclass class SystemMessage(Message): """便于支持OpenAI的消息 - Facilitate support for OpenAI messages + Facilitate support for OpenAI messages """ def __init__(self, content: str): - super().__init__(content, 'system') + super().__init__(content, "system") @dataclass class AIMessage(Message): """便于支持OpenAI的消息 - Facilitate support for OpenAI messages + Facilitate support for OpenAI messages """ def __init__(self, content: str): - super().__init__(content, 'assistant') + super().__init__(content, "assistant") -if __name__ == '__main__': - test_content = 'test_message' +if __name__ == "__main__": + test_content = "test_message" msgs = [ UserMessage(test_content), SystemMessage(test_content), AIMessage(test_content), - Message(test_content, role='QA') + Message(test_content, role="QA"), ] logger.info(msgs) From 230239b3e7fed3dabc21a9cf13568fde946cc1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 16:46:11 +0800 Subject: [PATCH 20/30] feat: +cache --- metagpt/memory/brain_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 8b1b31aae..e487a696d 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -55,7 +55,7 @@ class BrainMemory(pydantic.BaseModel): def history_text(self): if len(self.history) == 0: return "" - texts = [] + texts = [self.historical_summary] if self.historical_summary else [] for m in self.history[:-1]: if isinstance(m, Dict): t = Message(**m).content From 9220b131a433c8bf1f08a45053779832a7c275f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 17:08:19 +0800 Subject: [PATCH 21/30] feat: +cache --- metagpt/memory/brain_memory.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index e487a696d..ed2955902 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -67,21 +67,6 @@ class BrainMemory(pydantic.BaseModel): return "\n".join(texts) - def move_to_solution(self, history_summary): - """Put it in the solution queue for future long-term retrieval. - This functionality hasn't been added yet, so use the history summary as a temporary substitute for now.""" - pass - # if len(self.history) < 2: - # return - # msgs = self.history[:-1] - # self.solution.extend(msgs) - # if not Message(**self.history[-1]).is_contain(MessageType.Talk.value): - # self.solution.append(self.history[-1]) - # self.history = [] - # else: - # self.history = self.history[-1:] - # self.history.insert(0, Message(content="RESOLVED: " + history_summary)) - @property def last_talk(self): if len(self.history) == 0: @@ -119,3 +104,12 @@ class BrainMemory(pydantic.BaseModel): @staticmethod def to_redis_key(prefix: str, user_id: str, chat_id: str): return f"{prefix}:{chat_id}:{user_id}" + + async def set_history_summary(self, history_summary, redis_key, redis_conf): + if self.historical_summary == history_summary: + return + + self.historical_summary = history_summary + self.history = [] + await self.dumps(redis_key=redis_key, redis_conf=redis_conf) + self.is_dirty = False From f69f37bb0376b25f0d52eee2a68b72deac83391f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 17:09:02 +0800 Subject: [PATCH 22/30] feat: +cache --- metagpt/roles/assistant.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metagpt/roles/assistant.py b/metagpt/roles/assistant.py index 0bce4a3f9..9c80593f6 100644 --- a/metagpt/roles/assistant.py +++ b/metagpt/roles/assistant.py @@ -126,11 +126,13 @@ class Assistant(Role): if history_text == "": return last_talk history_summary = await self._llm.get_summary(history_text, max_words=500) + await self.memory.set_history_summary( + history_summary=history_summary, redis_key=CONFIG.REDIS_KEY, redis_conf=CONFIG.REDIS + ) if last_talk and await self._llm.is_related(last_talk, history_summary): # Merge relevant content. last_talk = await self._llm.rewrite(sentence=last_talk, context=history_text) return last_talk - self.memory.move_to_solution(history_summary) # Promptly clear memory after the issue is resolved. return last_talk @staticmethod From ec8e455a59ff1d669ae7071dd8129ddef0abf45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 17:47:33 +0800 Subject: [PATCH 23/30] feat: +cache --- metagpt/schema.py | 1 + 1 file changed, 1 insertion(+) diff --git a/metagpt/schema.py b/metagpt/schema.py index 987fccef2..8f8e4030f 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -37,6 +37,7 @@ class Message: sent_from: str = field(default="") send_to: str = field(default="") tags: Optional[Set] = field(default=None) + id: str = None def __str__(self): # prefix = '-'.join([self.role, str(self.cause_by)]) From ebe5217f701157b1fba5e23effc194c6d3ce8560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 17:58:40 +0800 Subject: [PATCH 24/30] feat: +cache --- metagpt/memory/brain_memory.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index ed2955902..8443d69d9 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -113,3 +113,10 @@ class BrainMemory(pydantic.BaseModel): self.history = [] await self.dumps(redis_key=redis_key, redis_conf=redis_conf) self.is_dirty = False + + def add_history(self, msg: Message): + if msg.id: + if int(msg.id) < int(self.last_history_id): + return + self.history.append(msg.dict()) + self.is_dirty = True From b5ea3c692f5988e2974c897cd21344ca40920e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 18:07:03 +0800 Subject: [PATCH 25/30] feat: +cache --- metagpt/memory/brain_memory.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 8443d69d9..027297eb8 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -120,3 +120,9 @@ class BrainMemory(pydantic.BaseModel): return self.history.append(msg.dict()) self.is_dirty = True + + def exists(self, text) -> bool: + for m in reversed(self.history): + if m.get("content") == text: + return True + return False From 4d9cfe6f439387ef783b3fe9b38edc4e3efe250d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 18:57:16 +0800 Subject: [PATCH 26/30] feat: +cache --- metagpt/memory/brain_memory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 027297eb8..2ea8ac209 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -14,6 +14,7 @@ from typing import Dict, List import pydantic from metagpt import Message +from metagpt.logs import logger from metagpt.utils.redis import Redis @@ -86,6 +87,7 @@ class BrainMemory(pydantic.BaseModel): if not redis.is_valid() or not redis_key: return BrainMemory() v = await redis.get(key=redis_key) + logger.info(f"REDIS GET {redis_key} {v}") if v: data = json.loads(v) bm = BrainMemory(**data) @@ -99,6 +101,7 @@ class BrainMemory(pydantic.BaseModel): return False v = self.json() await redis.set(key=redis_key, data=v, timeout_sec=timeout_sec) + logger.info(f"REDIS SET {redis_key} {v}") self.is_dirty = False @staticmethod From 26e35d799db5ff32c4a935909a15eb71b763e51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 19:02:54 +0800 Subject: [PATCH 27/30] feat: +cache --- metagpt/memory/brain_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 2ea8ac209..50c414c97 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -54,7 +54,7 @@ class BrainMemory(pydantic.BaseModel): @property def history_text(self): - if len(self.history) == 0: + if len(self.history) == 0 and not self.historical_summary: return "" texts = [self.historical_summary] if self.historical_summary else [] for m in self.history[:-1]: From 207ab965451a99689da72ad86fe361781c395300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 19:36:51 +0800 Subject: [PATCH 28/30] feat: +cache --- metagpt/memory/brain_memory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 50c414c97..6f4c3ec75 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -110,6 +110,9 @@ class BrainMemory(pydantic.BaseModel): async def set_history_summary(self, history_summary, redis_key, redis_conf): if self.historical_summary == history_summary: + if self.is_dirty: + await self.dumps(redis_key=redis_key, redis_conf=redis_conf) + self.is_dirty = False return self.historical_summary = history_summary From 63805c87f9c87de9b3823941a095b3f46b2f906b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 19:50:42 +0800 Subject: [PATCH 29/30] feat: +cache --- metagpt/memory/brain_memory.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index 6f4c3ec75..a974d95f6 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -31,9 +31,6 @@ class BrainMemory(pydantic.BaseModel): stack: List[Dict] = [] solution: List[Dict] = [] knowledge: List[Dict] = [] - # If the fingerprint of the history text is found in the `historical_summary_fingerprint`, - # it indicates that the text has already been incorporated into the `history summary`. - historical_summary_fingerprint: List[str] = [] historical_summary: str = "" last_history_id: str = "" is_dirty: bool = False From 4dd9f7743f0d8dd3d4b2deb53b7a4d5e56d8bedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Mon, 4 Sep 2023 19:53:35 +0800 Subject: [PATCH 30/30] feat: +cache --- metagpt/memory/brain_memory.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index a974d95f6..dedea3b41 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -5,8 +5,8 @@ @Author : mashenquan @File : brain_memory.py @Desc : Support memory for multiple tasks and multiple mainlines. +@Modified By: mashenquan, 2023/9/4. + redis memory cache. """ -import hashlib import json from enum import Enum from typing import Dict, List @@ -74,10 +74,6 @@ class BrainMemory(pydantic.BaseModel): return None return last_msg.content - @staticmethod - def get_md5(text: str) -> str: - return hashlib.md5(text.encode()).hexdigest() - @staticmethod async def loads(redis_key: str, redis_conf: Dict = None) -> "BrainMemory": redis = Redis(conf=redis_conf)