Add Luna.Memory with SQLite-backed persistent memory store
Implement IMemoryStore interface and MemoryStore using EF Core with SQLite for conversation and knowledge persistence. Includes DI service registration extensions.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Luna.Memory.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
extension(IServiceCollection services)
|
||||
{
|
||||
public IServiceCollection AddMemoryStore()
|
||||
{
|
||||
return services.AddSingleton<IMemoryStore, MemoryStore>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Luna.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for writes from the running agent
|
||||
/// </summary>
|
||||
public interface IMemoryStore
|
||||
{
|
||||
Task AddMemoryAsync(string memory);
|
||||
Task<string> GetMemoriesAsync();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.5" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.12.8" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Luna.Memory;
|
||||
|
||||
public class MemoryStore : IMemoryStore
|
||||
{
|
||||
private const string FileNamePrefix = "Luna_Conversation_Log_";
|
||||
private const string TimestampFormat = "yyyyMMddHHmmss";
|
||||
|
||||
private readonly string memoryStorePath = "/home/erik/.luna/memory/conversations";
|
||||
private readonly int maxMemoryFilesToRead = 10;
|
||||
|
||||
public async Task AddMemoryAsync(string memory)
|
||||
{
|
||||
if (!Directory.Exists(memoryStorePath))
|
||||
{
|
||||
Directory.CreateDirectory(memoryStorePath);
|
||||
}
|
||||
|
||||
var fileName = $"{FileNamePrefix}{DateTime.UtcNow.ToString(TimestampFormat)}";
|
||||
var filePath = Path.Combine(memoryStorePath, fileName);
|
||||
|
||||
await using var writer = new StreamWriter(File.Create(filePath));
|
||||
await writer.WriteAsync(memory);
|
||||
}
|
||||
|
||||
public async Task<string> GetMemoriesAsync()
|
||||
{
|
||||
if (!Directory.Exists(memoryStorePath))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var files = Directory.GetFiles(memoryStorePath)
|
||||
.OrderByDescending(GetTimeFromFileName)
|
||||
.ToArray();
|
||||
|
||||
if (files.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var filesToRead = files.Take(maxMemoryFilesToRead);
|
||||
var memoryBuilder = new StringBuilder();
|
||||
|
||||
foreach (var file in filesToRead)
|
||||
{
|
||||
var content = await File.ReadAllTextAsync(file);
|
||||
memoryBuilder.Append(content);
|
||||
}
|
||||
|
||||
return memoryBuilder.ToString();
|
||||
}
|
||||
|
||||
private DateTime GetTimeFromFileName(string filePath)
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
var timestamp = fileName[FileNamePrefix.Length..];
|
||||
return DateTime.ParseExact(timestamp, TimestampFormat, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user