From af38fa0fe6935b9208a4623928ba310aa6174a61 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 23:35:46 +0000 Subject: [PATCH] Fix expiration logic failure due to timestamp format mismatch The `expires_at` column is stored as an RFC3339 string (with 'T' separator and timezone info) by the Go driver. SQLite's `datetime('now')` returns a string with space separator and no timezone offset (UTC). Lexicographical comparison between these two formats was incorrect, causing expiring memories to persist indefinitely or expire prematurely depending on the context. This commit wraps `expires_at` in SQLite's `datetime()` function in all queries to normalize the format before comparison, ensuring correct expiration logic. --- src/plugin/internal/db/libsql.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugin/internal/db/libsql.go b/src/plugin/internal/db/libsql.go index 273c136..7611387 100644 --- a/src/plugin/internal/db/libsql.go +++ b/src/plugin/internal/db/libsql.go @@ -319,7 +319,7 @@ func (d *DB) cleanupExpired(ctx context.Context) error { d.mu.RUnlock() _, err := d.db.ExecContext(ctx, - `DELETE FROM memories WHERE expires_at IS NOT NULL AND expires_at < datetime('now')`, + `DELETE FROM memories WHERE expires_at IS NOT NULL AND datetime(expires_at) < datetime('now')`, ) return err } @@ -423,7 +423,7 @@ func (d *DB) Retrieve(ctx context.Context, namespace, key string) (*Memory, erro SELECT id, namespace, key, value, embedding, metadata, tags, created_at, updated_at, ttl, expires_at FROM memories WHERE namespace = ? AND key = ? - AND (expires_at IS NULL OR expires_at > datetime('now')) + AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) ` row := d.db.QueryRowContext(ctx, query, namespace, key) @@ -444,7 +444,7 @@ func (d *DB) RetrieveByID(ctx context.Context, id string) (*Memory, error) { SELECT id, namespace, key, value, embedding, metadata, tags, created_at, updated_at, ttl, expires_at FROM memories WHERE id = ? - AND (expires_at IS NULL OR expires_at > datetime('now')) + AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) ` row := d.db.QueryRowContext(ctx, query, id) @@ -588,7 +588,7 @@ func (d *DB) List(ctx context.Context, namespace string, limit, offset int) ([]* SELECT id, namespace, key, value, embedding, metadata, tags, created_at, updated_at, ttl, expires_at FROM memories WHERE namespace = ? - AND (expires_at IS NULL OR expires_at > datetime('now')) + AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) ORDER BY created_at DESC LIMIT ? OFFSET ? ` @@ -697,7 +697,7 @@ func (d *DB) Search(ctx context.Context, namespace string, queryEmbedding []floa FROM memories WHERE namespace = ? AND embedding IS NOT NULL - AND (expires_at IS NULL OR expires_at > datetime('now')) + AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) ` rows, err := d.db.QueryContext(ctx, query, namespace) @@ -766,7 +766,7 @@ func (d *DB) SearchAll(ctx context.Context, queryEmbedding []float32, limit int, SELECT id, namespace, key, value, embedding, metadata, tags, created_at, updated_at, ttl, expires_at FROM memories WHERE embedding IS NOT NULL - AND (expires_at IS NULL OR expires_at > datetime('now')) + AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) ` rows, err := d.db.QueryContext(ctx, query) @@ -821,7 +821,7 @@ func (d *DB) Count(ctx context.Context, namespace string) (int64, error) { var count int64 err := d.db.QueryRowContext(ctx, - `SELECT COUNT(*) FROM memories WHERE namespace = ? AND (expires_at IS NULL OR expires_at > datetime('now'))`, + `SELECT COUNT(*) FROM memories WHERE namespace = ? AND (expires_at IS NULL OR datetime(expires_at) > datetime('now'))`, namespace, ).Scan(&count) if err != nil { @@ -843,7 +843,7 @@ func (d *DB) CountAll(ctx context.Context) (int64, error) { var count int64 err := d.db.QueryRowContext(ctx, - `SELECT COUNT(*) FROM memories WHERE expires_at IS NULL OR expires_at > datetime('now')`, + `SELECT COUNT(*) FROM memories WHERE expires_at IS NULL OR datetime(expires_at) > datetime('now')`, ).Scan(&count) if err != nil { return 0, fmt.Errorf("failed to count memories: %w", err)