Public Access
Make meeting lifecycle stateful
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
using DiffPlex.DiffBuilder;
|
||||
using DiffPlex.DiffBuilder.Model;
|
||||
using MeetingAssistant.MeetingNotes;
|
||||
using System.Text;
|
||||
|
||||
namespace MeetingAssistant.Summary;
|
||||
|
||||
public sealed class SummaryAgentWriteAudit
|
||||
{
|
||||
private readonly MeetingSessionArtifacts artifacts;
|
||||
private readonly List<FileChange> changes = [];
|
||||
|
||||
public SummaryAgentWriteAudit(MeetingSessionArtifacts artifacts)
|
||||
{
|
||||
this.artifacts = artifacts;
|
||||
}
|
||||
|
||||
public async Task CaptureFileWriteAsync(
|
||||
string path,
|
||||
Func<Task> writeOperation,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var fullPath = Path.GetFullPath(path);
|
||||
var before = File.Exists(fullPath)
|
||||
? await File.ReadAllTextAsync(fullPath, cancellationToken)
|
||||
: "";
|
||||
await writeOperation();
|
||||
var after = File.Exists(fullPath)
|
||||
? await File.ReadAllTextAsync(fullPath, cancellationToken)
|
||||
: "";
|
||||
Capture(fullPath, before, after, cancellationToken);
|
||||
}
|
||||
|
||||
public void Capture(
|
||||
string path,
|
||||
string before,
|
||||
string after,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var fullPath = Path.GetFullPath(path);
|
||||
if (IsOwnedArtifact(fullPath) || string.Equals(before, after, StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var diffLines = CreateDiffLines(before, after);
|
||||
if (diffLines.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
changes.Add(new FileChange(fullPath, diffLines));
|
||||
}
|
||||
|
||||
public async Task AppendToAssistantContextAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (changes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.AssistantContextPath)!);
|
||||
var existing = File.Exists(artifacts.AssistantContextPath)
|
||||
? await File.ReadAllTextAsync(artifacts.AssistantContextPath, cancellationToken)
|
||||
: "";
|
||||
var builder = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(existing) && !existing.EndsWith(Environment.NewLine, StringComparison.Ordinal))
|
||||
{
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("## Summary Agent External File Changes");
|
||||
builder.AppendLine();
|
||||
foreach (var change in changes)
|
||||
{
|
||||
builder.AppendLine($"### {change.Path}");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("```diff");
|
||||
foreach (var line in change.DiffLines)
|
||||
{
|
||||
builder.AppendLine(line);
|
||||
}
|
||||
|
||||
builder.AppendLine("```");
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
await File.AppendAllTextAsync(artifacts.AssistantContextPath, builder.ToString(), cancellationToken);
|
||||
}
|
||||
|
||||
private bool IsOwnedArtifact(string fullPath)
|
||||
{
|
||||
return IsSamePath(fullPath, artifacts.SummaryPath) ||
|
||||
IsSamePath(fullPath, artifacts.AssistantContextPath);
|
||||
}
|
||||
|
||||
private static bool IsSamePath(string first, string second)
|
||||
{
|
||||
return string.Equals(
|
||||
Path.GetFullPath(first),
|
||||
Path.GetFullPath(second),
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static List<string> CreateDiffLines(string before, string after)
|
||||
{
|
||||
var model = InlineDiffBuilder.Diff(before, after);
|
||||
return model.Lines
|
||||
.Where(line => line.Type is ChangeType.Deleted or ChangeType.Inserted)
|
||||
.Select(line => $"{(line.Type == ChangeType.Inserted ? "+" : "-")} {line.Text}")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private sealed record FileChange(string Path, IReadOnlyList<string> DiffLines);
|
||||
}
|
||||
Reference in New Issue
Block a user