-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Memory validation fix + core_memory_replace runaway content repeating fix #1616
base: main
Are you sure you want to change the base?
Changes from all commits
dea560e
359775a
62ffc88
ca5be23
44c1965
fbed1e5
28b1172
b4dfba9
5e8c2fc
d3d0fe5
0af0ee5
df4ec2f
ce12a1a
3eef6d7
37ab165
e04c80a
ace4a5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
__version__ = "0.3.24" | ||
__version__ = "0.3.25" | ||
|
||
from memgpt.client.admin import Admin | ||
from memgpt.client.client import create_client |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import datetime | ||
import uuid | ||
import warnings | ||
from abc import ABC, abstractmethod | ||
from typing import List, Optional, Tuple, Union | ||
|
||
|
@@ -19,6 +20,7 @@ | |
) | ||
|
||
|
||
# always run validation | ||
class MemoryModule(BaseModel): | ||
"""Base class for memory modules""" | ||
|
||
|
@@ -28,13 +30,16 @@ class MemoryModule(BaseModel): | |
|
||
def __setattr__(self, name, value): | ||
"""Run validation if self.value is updated""" | ||
super().__setattr__(name, value) | ||
if name == "value": | ||
# run validation | ||
self.__class__.validate(self.dict(exclude_unset=True)) | ||
# Temporarily set the attribute to run validation | ||
temp = self.copy(update={name: value}) | ||
self.__class__.validate(temp.dict(exclude_unset=True)) | ||
|
||
super().__setattr__(name, value) | ||
|
||
@validator("value", always=True) | ||
@validator("value", always=True, check_fields=False) | ||
def check_value_length(cls, v, values): | ||
# TODO: this doesn't run all the time, should fix | ||
if v is not None: | ||
# Fetching the limit from the values dictionary | ||
limit = values.get("limit", 2000) # Default to 2000 if limit is not yet set | ||
|
@@ -48,10 +53,9 @@ def check_value_length(cls, v, values): | |
raise ValueError("Value must be either a string or a list of strings.") | ||
|
||
if length > limit: | ||
error_msg = f"Edit failed: Exceeds {limit} character limit (requested {length})." | ||
# TODO: add archival memory error? | ||
raise ValueError(error_msg) | ||
return v | ||
raise ValueError(f"Value exceeds {limit} character limit (requested {length}).") | ||
|
||
return v | ||
|
||
def __len__(self): | ||
return len(str(self)) | ||
|
@@ -71,10 +75,14 @@ def __init__(self): | |
self.memory = {} | ||
|
||
@classmethod | ||
def load(cls, state: dict): | ||
def load(cls, state: dict, catch_overflow: bool = True): | ||
"""Load memory from dictionary object""" | ||
obj = cls() | ||
for key, value in state.items(): | ||
# TODO: will cause an error for lists | ||
if catch_overflow and len(value["value"]) >= value["limit"]: | ||
warnings.warn(f"Loaded section {key} exceeds character limit {value['limit']} - increasing specified memory limit.") | ||
value["limit"] = len(value["value"]) | ||
obj.memory[key] = MemoryModule(**value) | ||
return obj | ||
|
||
|
@@ -93,6 +101,14 @@ def to_dict(self): | |
class ChatMemory(BaseMemory): | ||
|
||
def __init__(self, persona: str, human: str, limit: int = 2000): | ||
# TODO: clip if needed | ||
# if persona and len(persona) > limit: | ||
# warnings.warn(f"Persona exceeds {limit} character limit (requested {len(persona)}).") | ||
# persona = persona[:limit] | ||
|
||
# if human and len(human) > limit: | ||
# warnings.warn(f"Human exceeds {limit} character limit (requested {len(human)}).") | ||
# human = human[:limit] | ||
self.memory = { | ||
"persona": MemoryModule(name="persona", value=persona, limit=limit), | ||
"human": MemoryModule(name="human", value=human, limit=limit), | ||
|
@@ -124,7 +140,12 @@ def core_memory_replace(self, name: str, old_content: str, new_content: str) -> | |
Returns: | ||
Optional[str]: None is always returned as this function does not produce a response. | ||
""" | ||
self.memory[name].value = self.memory[name].value.replace(old_content, new_content) | ||
if old_content == "": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe give it a hint like "Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the ValueError that it gets |
||
raise ValueError( | ||
f"old_content can not be empty. Use core_memory_append to add new content without replacing any existing content." | ||
) | ||
else: | ||
self.memory[name].value = self.memory[name].value.replace(old_content, new_content) | ||
return None | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[tool.poetry] | ||
name = "pymemgpt" | ||
version = "0.3.24" | ||
version = "0.3.25" | ||
packages = [ | ||
{include = "memgpt"} | ||
] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused by what this code - what is it doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creates a copy of itself and runs validation on the value. Otherwise, even if the validation fails it still modifies the value and will go beyond the 2000 (or configured) limit.