Auto-Context: Semantische Kontext-Injektion, Memory-File-Embeddings, Agent-Toggle

- Automatische Embedding-basierte Kontext-Injektion vor jeder API-Anfrage
  (Top 5 Chat-Ergebnisse + Top 3 Memory-File-Treffer als recalled_context)
- Memory-Dateien (.md) werden embedded (Backfill + Live nach memory_write)
- Neue Agent-Option 'useAutoContext' (Checkbox, Default: aktiviert)
- VectorSearchService: SearchMemoryFilesAsync, EmbedMemoryFileAsync, Chunking
- EmbeddingBackgroundService: Memory-File-Backfill + EnqueueMemoryFile
- ToolService: memory_write löst Re-Embedding aus
- embeddingBg Parameter an ExecuteTool durchgereicht
This commit is contained in:
Meleki committed 2026-03-11 09:45:50 +01:00
1 parent add111ffe1
commit 148d1459a3
11 files changed
+305 -12

No files matched your search

+66 -3
View File
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
@@ -21,12 +22,14 @@ public class EmbeddingBackgroundService : BackgroundService
readonly string _dbConnectionString;
readonly ConcurrentQueue<EmbeddingJob> _queue = new();
readonly SemaphoreSlim _signal = new(0);
readonly string _dataPath;
public EmbeddingBackgroundService(VectorSearchService vectorSearch, EmbeddingService embedding, string dbPath)
{
_vectorSearch = vectorSearch;
_embedding = embedding;
_dbConnectionString = $"Data Source={dbPath}";
_dataPath = Path.GetDirectoryName(dbPath);
}
/// <summary>Enqueue eine neue Message zum Embedden.</summary>
@@ -50,6 +53,9 @@ public class EmbeddingBackgroundService : BackgroundService
// Backfill bestehender Messages
await BackfillAsync(ct);
// Memory-Dateien embedden
await BackfillMemoryFilesAsync(ct);
// Live-Embedding neuer Messages
Console.WriteLine("[EmbeddingBG] Waiting for new messages...");
while (!ct.IsCancellationRequested)
@@ -62,12 +68,21 @@ public class EmbeddingBackgroundService : BackgroundService
if (ct.IsCancellationRequested) break;
try
{
await _vectorSearch.EmbedMessageAsync(job.MessageId, job.ChainId, job.SessionId,
job.AgentId, job.Role, job.Text);
if (job.Role.StartsWith("memory:"))
{
// Memory-File-Embedding
var filePath = job.Role.Substring("memory:".Length);
await _vectorSearch.EmbedMemoryFileAsync(job.AgentId, filePath, job.Text);
}
else
{
await _vectorSearch.EmbedMessageAsync(job.MessageId, job.ChainId, job.SessionId,
job.AgentId, job.Role, job.Text);
}
}
catch (Exception ex)
{
Console.WriteLine($"[EmbeddingBG] Error embedding message {job.MessageId}: {ex.Message}");
Console.WriteLine($"[EmbeddingBG] Error embedding job: {ex.Message}");
}
}
}
@@ -133,6 +148,54 @@ public class EmbeddingBackgroundService : BackgroundService
Console.WriteLine($"[EmbeddingBG] Backfill complete: {embedded} new embeddings, {skipped} skipped, {total} total messages.");
}
async Task BackfillMemoryFilesAsync(CancellationToken ct)
{
Console.WriteLine("[EmbeddingBG] Starting memory file backfill...");
var agentsDir = Path.Combine(_dataPath, "agents");
if (!Directory.Exists(agentsDir))
{
Console.WriteLine("[EmbeddingBG] No agents directory found, skipping memory backfill.");
return;
}
int total = 0;
foreach (var agentDir in Directory.GetDirectories(agentsDir))
{
if (ct.IsCancellationRequested) break;
var agentId = Path.GetFileName(agentDir);
// Alle .md Dateien im Agent-Verzeichnis (rekursiv)
var mdFiles = Directory.GetFiles(agentDir, "*.md", SearchOption.AllDirectories);
foreach (var mdFile in mdFiles)
{
if (ct.IsCancellationRequested) break;
try
{
var text = await File.ReadAllTextAsync(mdFile, ct);
if (string.IsNullOrWhiteSpace(text) || text.Length < 10) continue;
var relativePath = Path.GetRelativePath(agentDir, mdFile);
await _vectorSearch.EmbedMemoryFileAsync(agentId, relativePath, text);
total++;
}
catch (Exception ex)
{
Console.WriteLine($"[EmbeddingBG] Error embedding memory file {mdFile}: {ex.Message}");
}
}
}
Console.WriteLine($"[EmbeddingBG] Memory file backfill complete: {total} files embedded.");
}
/// <summary>Embeddet eine einzelne Memory-Datei (nach memory_write).</summary>
public void EnqueueMemoryFile(string agentId, string filePath, string text)
{
_queue.Enqueue(new EmbeddingJob(0, "", "", agentId, "memory:" + filePath, text));
_signal.Release();
}
record EmbeddingJob(long MessageId, string ChainId, string SessionId, string AgentId, string Role, string Text);
class BackfillRow