diff --git a/mcp/event.go b/mcp/event.go index 62dd2ad2..80b42f51 100644 --- a/mcp/event.go +++ b/mcp/event.go @@ -376,10 +376,11 @@ func (s *MemoryEventStore) purge() { for _, dl := range sm { if dl.size > 0 { r := dl.removeFirst() - if r > 0 { - changed = true - s.nBytes -= r - } + // Even if we remove an empty chunk, that's + // still progress. There may be non-empty + // chunks after it. + changed = true + s.nBytes -= r } } } diff --git a/mcp/event_test.go b/mcp/event_test.go index 685e6486..91ddb9d7 100644 --- a/mcp/event_test.go +++ b/mcp/event_test.go @@ -327,6 +327,29 @@ func TestMemoryEventStoreAfter(t *testing.T) { } } +func TestMemoryEventStorePurgeEmpty(t *testing.T) { + ctx := context.Background() + s := NewMemoryEventStore(nil) + s.SetMaxBytes(100) + + // Append an empty chunk first. + if err := s.Append(ctx, "S1", "1", []byte("")); err != nil { + t.Fatal(err) + } + // Append a non-empty chunk. + if err := s.Append(ctx, "S1", "1", []byte("1234567890")); err != nil { + t.Fatal(err) + } + // Now nBytes = 10, but the first chunk is empty. + + // This should not panic. + s.SetMaxBytes(5) + + if s.nBytes > 5 { + t.Errorf("got nBytes %d, want <= 5", s.nBytes) + } +} + func BenchmarkMemoryEventStore(b *testing.B) { // Benchmark with various settings for event store size, number of session, // and payload size.