MemorySystemTests.cscsharp

Documentation

Version 3 design tests

Automated checks for chat, history, and Kokoro TTS (sanitizer + optional live speech).

Quick run

python src/Version3/DesignTests/run-design-tests.py
python src/Version3/DesignTests/run-design-tests.py --live
.\src\Version3\DesignTests\run-design-tests.ps1 -Live

What runs

| Suite | Needs network | Covers | |-------|----------------|--------| | ChatHistoryStoreTests | No | Same as V1 history XML | | OllamaClientHistoryTests | No | Client save/load | | KokoroTtsSanitizerTests | No | Markdown/emoji/URL stripping for speech | | OllamaLiveTests | Yes (--live) | Ollama chat | | KokoroTtsLiveTests | Yes (--live) | Kokoro model load + SpeakAsync |

First Kokoro live run may download ~320MB of model weights.

Console video (testers)

Record Version 3 console sessions (chat + TTS + history):

python src/TestManager/test_manager.py record v2 chat-tts --build

See src/TestManager/README.md.

All versions

python src/run-all-design-tests.py
python src/run-all-design-tests.py --live
using System;using System.IO;using System.Linq;using System.Threading.Tasks;using Agent.Core.Memory;using Agent.Core.Ollama;using Xunit;namespace Agent.Core.DesignTests;public class MemorySystemTests{    private class MockOllamaClient : OllamaClient    {        public Func<string, float[]>? OnGetEmbedding { get; set; }        public MockOllamaClient() : base(new Logging.Logger(_ => { }))        {        }        public override Task<float[]> GetEmbeddingAsync(string prompt, string? modelOverride = null)        {            if (OnGetEmbedding != null)            {                return Task.FromResult(OnGetEmbedding(prompt));            }            return Task.FromResult(new float[] { 0.1f, 0.2f, 0.3f });        }    }    [Fact]    public void CosineSimilarity_calculates_correct_value()    {        float[] vecA = { 1.0f, 0.0f, 0.0f };        float[] vecB = { 1.0f, 0.0f, 0.0f };        float[] vecC = { 0.0f, 1.0f, 0.0f };        Assert.Equal(1.0f, MemoryManager.CosineSimilarity(vecA, vecB), 5);        Assert.Equal(0.0f, MemoryManager.CosineSimilarity(vecA, vecC), 5);    }    [Fact]    public async Task MemoryManager_stores_and_loads_hierarchical_json()    {        string tempFile = Path.Combine(Path.GetTempPath(), "memory_test_" + Path.GetRandomFileName() + ".json");        var client = new MockOllamaClient();                // Setup deterministic mock embeddings based on text content to verify similarity        client.OnGetEmbedding = text =>        {            if (text.Contains("Alice")) return new float[] { 1.0f, 0.0f };            if (text.Contains("Bob")) return new float[] { 0.0f, 1.0f };            return new float[] { 0.5f, 0.5f };        };        try        {            var manager = new MemoryManager(tempFile, client);            // 1. Store dynamic branches and leaves            await manager.StoreAsync("user/name", "Alice");            await manager.StoreAsync("user/settings/theme", "dark");            await manager.StoreAsync("system/version", "6.0");            // Verify file was written            Assert.True(File.Exists(tempFile));            string jsonContent = File.ReadAllText(tempFile);                        // Should contain hierarchy            Assert.Contains("\"user\"", jsonContent);            Assert.Contains("\"settings\"", jsonContent);            Assert.Contains("\"theme\"", jsonContent);            Assert.Contains("\"value\": \"Alice\"", jsonContent);            // 2. Load it back into a new manager            var manager2 = new MemoryManager(tempFile, client);            Assert.Equal(3, manager2.Leaves.Count);            // Verify paths and values are preserved            Assert.Equal("Alice", manager2.QueryPath("user/name"));            Assert.Equal("dark", manager2.QueryPath("user/settings/theme"));            Assert.Equal("6.0", manager2.QueryPath("system/version"));            // 3. Test retrieve semantic search            // Query closest to Alice            var matchesAlice = await manager2.RetrieveAsync("Who is Alice?", topN: 1);            Assert.Single(matchesAlice);            Assert.Equal("user/name", matchesAlice[0].Path);            Assert.Equal("Alice", matchesAlice[0].Value);        }        finally        {            if (File.Exists(tempFile)) File.Delete(tempFile);        }    }}