Portal Community

Retention Policy Configuration

// Per-agent retention policy
public class EpisodicRetentionPolicy
{
    public int ActiveRetentionDays { get; set; } = 90;   // full data kept 90 days
    public int ArchiveRetentionDays { get; set; } = 365; // summaries kept 1 year
    public bool ArchiveOnExpiry { get; set; } = true;    // archive vs. delete
    public bool DeleteAfterArchivalPeriod { get; set; } = true; // hard delete after 1yr
}

Retention Lifecycle

1

Active (0–90 days)

Full episode data — messages, tool calls, embedding. All recall modes available including message-level retrieval.

2

Archived (90–365 days)

MessagesJson and ToolCallsJson are cleared. Only Summary and SummaryEmbedding retained. Semantic recall still works; message-level recall returns "archived".

3

Deleted (>365 days)

Row is deleted from the table. No recall possible. Summaries are no longer available.

MemoryRetentionJob

// Runs nightly as a background service
public class MemoryRetentionJob : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            var cutoffArchive = DateTimeOffset.UtcNow.AddDays(-_policy.ActiveRetentionDays);
            var cutoffDelete  = DateTimeOffset.UtcNow.AddDays(-_policy.ArchiveRetentionDays);

            // Archive: clear message content, keep summary
            await _db.Episodes
                .Where(e => e.EndedAt < cutoffArchive && !e.IsArchived)
                .ExecuteUpdateAsync(s => s
                    .SetProperty(e => e.MessagesJson, "[]")
                    .SetProperty(e => e.ToolCallsJson, "[]")
                    .SetProperty(e => e.IsArchived, true));

            // Delete: hard delete very old episodes
            await _db.Episodes
                .Where(e => e.EndedAt < cutoffDelete && e.IsArchived)
                .ExecuteDeleteAsync();

            await Task.Delay(TimeSpan.FromHours(24), ct);
        }
    }
}

Cross-Session Semantic Recall after Archival

Even after a session is archived (messages cleared), the summary embedding remains. The agent can still "remember" that a topic was discussed without knowing the exact content — the summary provides sufficient context for recall:

// A recalled archived episode looks like:
new EpisodeSnippet {
    EpisodeId = Guid.Parse("..."),
    Summary = "User inquired about annual leave balance for 2025. Agent confirmed 12 days remaining.",
    Date = new DateTimeOffset(2025, 3, 14, ...),
    RelevanceScore = 0.87f,
    IsArchived = true   // signals that full message content is unavailable
}