Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
see @docs/AGENTS.md

Ignore the "archived" directory.
- Follow @docs/AGENTS.md instructions without exceptions
- Ignore the "archived" directory

# Definition of done

- `format.sh` is passing without errors or warnings
- `build.sh` is passing without errors or warnings
- Test coverage is greater than 80% and `coverage.sh` is not failing
- Problems are not hidden, problems are addressed.
- Report breaking changes and ask how to handle them, do not assume migrations are required.
- `coverage.sh` is passing without errors or warnings, coverage > 80% (use coverage reports to find which code is not covered)

# C# Code Style

- Use .NET 10 and C# 14
- Always use `this.` prefix
- Async methods have mandatory `Async` name suffix (optional only for tests, not required for `Main` method)
- Keep magic values and constants in a centralized `Constants.cs` file
- One class per file, matching the class name with the file name
- Sort class methods by visibility: public first, private at the end
Expand Down
105 changes: 78 additions & 27 deletions coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ MIN_COVERAGE=${1:-80}
echo "Running tests with coverage collection..."
echo ""

# Clean previous results
rm -rf ./TestResults

# Run tests with coverage using coverlet.collector
# --collect:"XPlat Code Coverage" enables the collector
# --results-directory specifies output location
Expand All @@ -23,39 +26,87 @@ echo ""
echo "Coverage collection complete!"
echo ""

# Find the most recent coverage file (coverlet.collector creates it in a GUID subfolder)
COVERAGE_REPORT=$(find ./TestResults -name "coverage.cobertura.xml" | head -1)
# Find all coverage files
COVERAGE_FILES=$(find ./TestResults -name "coverage.cobertura.xml" | sort)
FILE_COUNT=$(echo "$COVERAGE_FILES" | wc -l | tr -d ' ')

echo "Coverage report location: $COVERAGE_REPORT"
echo "Found $FILE_COUNT coverage report(s)"
echo ""

if [ -f "$COVERAGE_REPORT" ]; then
# Parse line coverage from cobertura XML
LINE_RATE=$(grep -o 'line-rate="[0-9.]*"' "$COVERAGE_REPORT" | head -1 | grep -o '[0-9.]*')

if [ -n "$LINE_RATE" ]; then
# Convert to percentage
COVERAGE_PCT=$(awk "BEGIN {printf \"%.2f\", $LINE_RATE * 100}")

echo "====================================="
echo " Test Coverage: ${COVERAGE_PCT}%"
echo " Threshold: ${MIN_COVERAGE}%"
echo "====================================="
echo ""

# Check if coverage meets threshold
MEETS_THRESHOLD=$(awk "BEGIN {print ($COVERAGE_PCT >= $MIN_COVERAGE) ? 1 : 0}")
# Parse and display coverage for each project
declare -a COVERAGE_RATES
declare -a COVERAGE_SOURCES
declare -a PROJECT_NAMES

while IFS= read -r COVERAGE_FILE; do
if [ -f "$COVERAGE_FILE" ]; then
# Extract source path and line rate
SOURCE=$(grep -o '<source>.*</source>' "$COVERAGE_FILE" | head -1 | sed 's/<source>//;s/<\/source>//')
LINE_RATE=$(grep -o 'line-rate="[0-9.]*"' "$COVERAGE_FILE" | head -1 | grep -o '[0-9.]*')

if [ "$MEETS_THRESHOLD" -eq 0 ]; then
echo "❌ Coverage ${COVERAGE_PCT}% is below minimum threshold of ${MIN_COVERAGE}%"
exit 1
else
echo "βœ… Coverage meets minimum threshold"
rm -rf TestResults
if [ -n "$LINE_RATE" ]; then
COVERAGE_PCT=$(awk "BEGIN {printf \"%.2f\", $LINE_RATE * 100}")

# Determine project name from source path
if [[ "$SOURCE" == *"/Core/"* ]] || [[ "$SOURCE" == *"/Core" ]]; then
PROJECT_NAME="Core"
# Only track Core and Main for threshold checking (exclude Combined)
COVERAGE_RATES+=("$COVERAGE_PCT")
COVERAGE_SOURCES+=("$SOURCE")
PROJECT_NAMES+=("$PROJECT_NAME")
elif [[ "$SOURCE" == *"/Main/"* ]] || [[ "$SOURCE" == *"/Main" ]]; then
PROJECT_NAME="Main"
# Only track Core and Main for threshold checking (exclude Combined)
COVERAGE_RATES+=("$COVERAGE_PCT")
COVERAGE_SOURCES+=("$SOURCE")
PROJECT_NAMES+=("$PROJECT_NAME")
else
PROJECT_NAME="Combined (includes untestable entry points)"
# Skip adding to COVERAGE_RATES - we don't check threshold for Combined
fi

echo " $PROJECT_NAME: ${COVERAGE_PCT}%"
fi
fi
done <<< "$COVERAGE_FILES"

echo ""

# Calculate minimum coverage across Core and Main assemblies only
# (Combined report is excluded as it includes untestable entry points like Program.Main)
MIN_PROJECT_COVERAGE=""
MIN_PROJECT_NAME=""
for i in "${!COVERAGE_RATES[@]}"; do
rate="${COVERAGE_RATES[$i]}"
if [ -z "$MIN_PROJECT_COVERAGE" ] || (( $(awk "BEGIN {print ($rate < $MIN_PROJECT_COVERAGE) ? 1 : 0}") )); then
MIN_PROJECT_COVERAGE="$rate"
MIN_PROJECT_NAME="${PROJECT_NAMES[$i]}"
fi
done

if [ -n "$MIN_PROJECT_COVERAGE" ]; then
echo "====================================="
echo " Minimum Coverage: ${MIN_PROJECT_COVERAGE}%"
echo " Threshold: ${MIN_COVERAGE}%"
echo "====================================="
echo ""

# Check if coverage meets threshold
MEETS_THRESHOLD=$(awk "BEGIN {print ($MIN_PROJECT_COVERAGE >= $MIN_COVERAGE) ? 1 : 0}")

if [ "$MEETS_THRESHOLD" -eq 0 ]; then
echo "❌ Coverage ${MIN_PROJECT_COVERAGE}% is below minimum threshold of ${MIN_COVERAGE}%"
echo ""
echo "Coverage by project:"
for i in "${!COVERAGE_RATES[@]}"; do
echo " - ${COVERAGE_SOURCES[$i]}: ${COVERAGE_RATES[$i]}%"
done
exit 1
else
echo "⚠️ Could not parse coverage percentage from report"
echo "βœ… All projects meet minimum threshold"
rm -rf TestResults
fi
else
echo "⚠️ Coverage report not found at: $COVERAGE_REPORT"
echo "⚠️ Could not parse coverage from reports"
exit 1
fi
2 changes: 2 additions & 0 deletions km.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
dotnet run --project src/Main/Main.csproj -- "$@"
9 changes: 5 additions & 4 deletions mem.slnx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
ο»Ώ<Solution>
<Solution>
<Folder Name="/tests/">
<Project Path="tests\Core.Tests\Core.Tests.csproj" Type="Classic C#" />
<Project Path="tests/Main.Tests/Main.Tests.csproj" />
<Project Path="tests\Core.Tests\Core.Tests.csproj" />
</Folder>
<Project Path="src\Core\Core.csproj" Type="Classic C#" />
<Project Path="src\Main\Main.csproj" Type="Classic C#" />
<Project Path="src\Core\Core.csproj" />
<Project Path="src\Main\Main.csproj" />
</Solution>
3 changes: 3 additions & 0 deletions src/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ file_header_template = Copyright (c) Microsoft. All rights reserved.
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
file_header_template = Copyright (c) Microsoft. All rights reserved.
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
Expand Down Expand Up @@ -394,6 +395,8 @@ resharper_Arrange_Type_Modifiers_highlighting = none
resharper_Arrange_Type_Member_Modifiers_highlighting = none
# InconsistentNaming
resharper_Inconsistent_Naming_highlighting = none
# GrammarMistakeInComment
resharper_Grammar_Mistake_In_Comment_highlighting = none


# CA1056: URI properties should not be strings
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/AppConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Cache;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Cache/CacheConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/ConfigParser.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;
using KernelMemory.Core.Config.Cache;
using KernelMemory.Core.Config.ContentIndex;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/ContentIndex/ContentIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/ContentIndex/PostgresContentIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/ContentIndex/SqliteContentIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Embeddings/AzureOpenAIEmbeddingsConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Embeddings/EmbeddingsConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Embeddings/OllamaEmbeddingsConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Embeddings/OpenAIEmbeddingsConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/CacheTypes.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/ContentIndexTypes.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/EmbeddingsTypes.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/NodeAccessLevels.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/SearchIndexTypes.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/StorageTypes.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Enums/VectorMetrics.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;

namespace KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/NodeConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.ContentIndex;
using KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/SearchIndex/FtsSearchIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/SearchIndex/GraphSearchIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Validation;

Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/SearchIndex/SearchIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Embeddings;
using KernelMemory.Core.Config.Enums;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/SearchIndex/VectorSearchIndexConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Storage/AzureBlobStorageConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Storage/DiskStorageConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Storage/StorageConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json.Serialization;
using KernelMemory.Core.Config.Enums;
using KernelMemory.Core.Config.Validation;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Validation/ConfigException.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
namespace KernelMemory.Core.Config.Validation;

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Core/Config/Validation/IValidatable.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
namespace KernelMemory.Core.Config.Validation;

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="KernelMemory.Main.Tests" />
<InternalsVisibleTo Include="KernelMemory.Core.Tests" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/Core/Storage/ContentStorageDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Globalization;
using KernelMemory.Core.Storage.Entities;
using Microsoft.EntityFrameworkCore;
Expand Down
33 changes: 33 additions & 0 deletions src/Core/Storage/ContentStorageService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using System.Text.Json;
using KernelMemory.Core.Storage.Entities;
Expand Down Expand Up @@ -153,6 +154,38 @@ public async Task<long> CountAsync(CancellationToken cancellationToken = default
return await this._context.Content.LongCountAsync(cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Lists content records with pagination support.
/// </summary>
/// <param name="skip">Number of records to skip.</param>
/// <param name="take">Number of records to take.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>List of content DTOs.</returns>
public async Task<List<ContentDto>> ListAsync(int skip, int take, CancellationToken cancellationToken = default)
{
var records = await this._context.Content
.AsNoTracking()
.OrderByDescending(c => c.RecordCreatedAt)
.Skip(skip)
.Take(take)
.ToListAsync(cancellationToken).ConfigureAwait(false);

return records.Select(record => new ContentDto
{
Id = record.Id,
Content = record.Content,
MimeType = record.MimeType,
ByteSize = record.ByteSize,
ContentCreatedAt = record.ContentCreatedAt,
RecordCreatedAt = record.RecordCreatedAt,
RecordUpdatedAt = record.RecordUpdatedAt,
Title = record.Title,
Description = record.Description,
Tags = record.Tags,
Metadata = record.Metadata
}).ToList();
}

// ========== Phase 1: Queue Operations (REQUIRED) ==========

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Core/Storage/CuidGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using Visus.Cuid;

namespace KernelMemory.Core.Storage;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Storage/Entities/ContentRecord.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;

namespace KernelMemory.Core.Storage.Entities;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Storage/Entities/OperationRecord.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;

namespace KernelMemory.Core.Storage.Entities;
Expand Down
1 change: 1 addition & 0 deletions src/Core/Storage/Exceptions/ContentStorageException.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
namespace KernelMemory.Core.Storage.Exceptions;

/// <summary>
Expand Down
Loading
Loading