From 45d6caf723dc31f3e32f3e6380800ebfb08e94bc Mon Sep 17 00:00:00 2001 From: phernandez Date: Wed, 24 Dec 2025 13:41:28 -0600 Subject: [PATCH] fix: remove MaxLen constraint from observation content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API Pydantic schema had a MaxLen(1000) constraint on observation content while the database uses SQLAlchemy's Text type (unlimited). This mismatch caused validation errors when observations exceeded 1000 characters (e.g., JSON schemas with 1458+ chars). Removed the MaxLen constraint to match the DB schema. Retained: - BeforeValidator(str.strip) for whitespace cleaning - MinLen(1) to ensure non-empty content Added comprehensive tests to verify: - Long content (10K+ chars) is accepted - Very long content (50K+ chars) is accepted - Empty/whitespace-only content is still rejected - Whitespace stripping still works Fixes #385 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 Signed-off-by: phernandez --- src/basic_memory/schemas/base.py | 2 +- tests/schemas/test_schemas.py | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/basic_memory/schemas/base.py b/src/basic_memory/schemas/base.py index 5219fdc8..da2caf16 100644 --- a/src/basic_memory/schemas/base.py +++ b/src/basic_memory/schemas/base.py @@ -183,7 +183,7 @@ ObservationStr = Annotated[ str, BeforeValidator(str.strip), # Clean whitespace MinLen(1), # Ensure non-empty after stripping - MaxLen(1000), # Keep reasonable length + # No MaxLen - matches DB Text column which has no length restriction ] diff --git a/tests/schemas/test_schemas.py b/tests/schemas/test_schemas.py index ed7377f0..4e981abf 100644 --- a/tests/schemas/test_schemas.py +++ b/tests/schemas/test_schemas.py @@ -466,3 +466,45 @@ class TestTimeframeParsing: # They should be approximately the same time (within an hour due to parsing differences) time_diff = abs((today_parsed - oneday_parsed).total_seconds()) assert time_diff < 3600, f"'today' and '1d' should be similar times, diff: {time_diff}s" + + +class TestObservationContentLength: + """Test observation content length validation matches DB schema.""" + + def test_observation_accepts_long_content(self): + """Observation content should accept unlimited length to match DB Text column.""" + from basic_memory.schemas.base import Observation + + # Very long content that would have failed with old MaxLen(1000) limit + long_content = "x" * 10000 + + obs = Observation(category="test", content=long_content) + assert len(obs.content) == 10000 + + def test_observation_accepts_very_long_content(self): + """Observation content should accept very long content like JSON schemas.""" + from basic_memory.schemas.base import Observation + + # Simulate the JSON schema content from issue #385 (1458+ chars) + json_schema_content = '{"$schema": "http://json-schema.org/draft-07/schema#"' + "x" * 50000 + + obs = Observation(category="schema", content=json_schema_content) + assert len(obs.content) > 50000 + + def test_observation_still_requires_non_empty_content(self): + """Observation content must still be non-empty after stripping.""" + from basic_memory.schemas.base import Observation + from pydantic import ValidationError + + with pytest.raises(ValidationError): + Observation(category="test", content="") + + with pytest.raises(ValidationError): + Observation(category="test", content=" ") # whitespace only + + def test_observation_strips_whitespace(self): + """Observation content should have whitespace stripped.""" + from basic_memory.schemas.base import Observation + + obs = Observation(category="test", content=" some content ") + assert obs.content == "some content"