Expand settings and logs agent tools
PR and Push Build/Test / build-and-test (push) Successful in 9m36s

This commit is contained in:
2026-06-01 21:07:08 +02:00
parent abac46c691
commit 11c65ce669
12 changed files with 1160 additions and 45 deletions
@@ -1,6 +1,7 @@
using MeetingAssistant.Workflow;
using MeetingAssistant.Logging;
using MeetingAssistant.Speakers;
using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@@ -298,6 +299,167 @@ public sealed class WorkflowRulesEditorTests
Assert.StartsWith("Refused:", await tools.WriteProjectFile("Alpha", "../escape.md", "bad"));
}
[Fact]
public async Task SettingsToolsListReadAndSearchMeetingArtifacts()
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
var summariesRoot = Path.Combine(root, "Summaries");
var transcriptsRoot = Path.Combine(root, "Transcripts");
var notesRoot = Path.Combine(root, "Notes");
var contextRoot = Path.Combine(root, "Context");
Directory.CreateDirectory(summariesRoot);
Directory.CreateDirectory(transcriptsRoot);
Directory.CreateDirectory(notesRoot);
Directory.CreateDirectory(contextRoot);
await File.WriteAllTextAsync(
Path.Combine(summariesRoot, "20260530-1000-summary.md"),
"""
---
title: Older Meeting
start_time: "2026-05-30T10:00:00+02:00"
meeting: "[[20260530-1000-note|Meeting Note]]"
transcript: "[[20260530-1000-transcript|Transcript]]"
assistant_context: "[[20260530-1000-context|Assistant Context]]"
projects:
- Alpha
---
older summary needle
""");
await File.WriteAllTextAsync(
Path.Combine(summariesRoot, "20260531-0900-summary.md"),
"""
---
title: Newer Meeting
start_time: "2026-05-31T09:00:00+02:00"
meeting: "[[20260531-0900-note|Meeting Note]]"
transcript: "[[20260531-0900-transcript|Transcript]]"
assistant_context: "[[20260531-0900-context|Assistant Context]]"
projects:
- Beta
---
newer summary needle
""");
await File.WriteAllTextAsync(Path.Combine(notesRoot, "20260531-0900-note.md"), "note one\nnote needle\nnote three");
await File.WriteAllTextAsync(Path.Combine(transcriptsRoot, "20260531-0900-transcript.md"), "transcript one\ntranscript needle\ntranscript three");
await File.WriteAllTextAsync(Path.Combine(contextRoot, "20260531-0900-context.md"), "context one\ncontext needle\ncontext three");
var tools = new WorkflowRulesEditorTools(new MeetingAssistantOptions
{
Vault =
{
SummariesFolder = summariesRoot,
TranscriptsFolder = transcriptsRoot,
MeetingNotesFolder = notesRoot,
AssistantContextFolder = contextRoot
}
});
var recent = await tools.ListRecentSummaries(limit: 2);
var summary = await tools.ReadSummary("20260531-0900-summary.md", tail: 1);
var transcript = await tools.ReadTranscript("20260531-0900-transcript.md", from: 2, to: 2);
var meetingNote = await tools.ReadMeetingNote("20260531-0900-note.md", tail: 2);
var context = await tools.ReadContext("20260531-0900-context.md", tail: 2);
var summarySearch = await tools.SearchSummaries("needle");
var transcriptSearch = await tools.SearchTranscripts("needle");
var noteSearch = await tools.SearchMeetingNotes("needle");
var contextSearch = await tools.SearchContext("needle");
Assert.True(recent.IndexOf("20260531-0900-summary.md", StringComparison.Ordinal) <
recent.IndexOf("20260530-1000-summary.md", StringComparison.Ordinal));
Assert.Contains("title: Newer Meeting", recent);
Assert.Contains("meeting_note: 20260531-0900-note.md", recent);
Assert.Contains("transcript: 20260531-0900-transcript.md", recent);
Assert.Contains("context: 20260531-0900-context.md", recent);
Assert.Equal("newer summary needle", summary.Trim());
Assert.Equal("transcript needle", transcript.Trim());
Assert.Equal("note needle\nnote three", meetingNote);
Assert.Equal("context needle\ncontext three", context);
Assert.Contains("20260531-0900-summary.md:", summarySearch);
Assert.Contains("20260531-0900-transcript.md:2 transcript needle", transcriptSearch);
Assert.Contains("20260531-0900-note.md:2 note needle", noteSearch);
Assert.Contains("20260531-0900-context.md:2 context needle", contextSearch);
Assert.StartsWith("Refused:", await tools.ReadSummary("../escape.md"));
}
[Fact]
public async Task SettingsToolsWriteMeetingArtifactsAndFrontmatter()
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
var summariesRoot = Path.Combine(root, "summaries");
var transcriptsRoot = Path.Combine(root, "transcripts");
var notesRoot = Path.Combine(root, "meetings");
var contextRoot = Path.Combine(root, "context");
Directory.CreateDirectory(summariesRoot);
Directory.CreateDirectory(transcriptsRoot);
Directory.CreateDirectory(notesRoot);
Directory.CreateDirectory(contextRoot);
await File.WriteAllTextAsync(
Path.Combine(notesRoot, "daily.md"),
"""
---
title: Old
---
Existing body.
""");
await File.WriteAllTextAsync(Path.Combine(transcriptsRoot, "daily-transcript.md"), "one\nthree");
var tools = new WorkflowRulesEditorTools(new MeetingAssistantOptions
{
Vault =
{
SummariesFolder = summariesRoot,
TranscriptsFolder = transcriptsRoot,
MeetingNotesFolder = notesRoot,
AssistantContextFolder = contextRoot
}
});
Assert.Equal("daily-summary.md", await tools.WriteSummary("daily-summary.md", "summary body", replace_file: true));
Assert.Equal("daily-transcript.md", await tools.WriteTranscript("daily-transcript.md", "two", insert: 2));
Assert.Equal("daily.md", await tools.WriteMeetingNoteFrontmatter(
"daily.md",
"""
title: Fixed
projects:
- Alpha
transcript: "[[daily-transcript|Transcript]]"
"""));
Assert.Equal("repair/context.md", await tools.WriteContext("repair/context.md", "context body"));
Assert.Equal("summary body", await File.ReadAllTextAsync(Path.Combine(summariesRoot, "daily-summary.md")));
Assert.Equal("one\ntwo\nthree", await File.ReadAllTextAsync(Path.Combine(transcriptsRoot, "daily-transcript.md")));
var note = await File.ReadAllTextAsync(Path.Combine(notesRoot, "daily.md"));
Assert.Contains("title: Fixed", note);
Assert.Contains("projects:\n- Alpha", note);
Assert.Contains("Existing body.", note);
Assert.Equal("context body", await File.ReadAllTextAsync(Path.Combine(contextRoot, "repair", "context.md")));
Assert.StartsWith("Refused:", await tools.WriteSummary("../escape.md", "bad"));
Assert.StartsWith("Refused:", await tools.WriteMeetingNoteFrontmatter("daily.md", "title: ["));
}
[Fact]
public async Task SettingsToolsExposeDiagnosticsWithoutHttp()
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["MeetingAssistant:Automation:RulesPath"] = "rules.yaml"
})
.Build();
var tools = new WorkflowRulesEditorTools(
new MeetingAssistantOptions(),
configuration: config);
Assert.Contains("meeting-assistant", tools.GetHealth());
Assert.Equal("Recording coordinator is not configured.", tools.GetRecordingStatus());
Assert.Contains("rules.yaml", tools.ReloadWorkflowConfiguration());
Assert.Equal("Meeting metadata provider is not configured.", await tools.DiagnoseCurrentMeeting());
Assert.Equal("Speaker identity merge service is not configured.", await tools.MergeRecentSpeakerIdentities());
Assert.Equal("ASR diagnostic service is not configured.", await tools.DiagnoseAsrTranscribeFile("missing.wav"));
Assert.Equal("ASR diagnostic service is not configured.", await tools.DiagnoseAsrDiarizeFile("missing.wav"));
}
[Fact]
public void FileLoggerRotatesCurrentLogAndKeepsFourOlderFiles()
{
@@ -398,6 +560,7 @@ public sealed class WorkflowRulesEditorTests
Assert.Contains("read_config", instructions);
Assert.Contains("read_logs", instructions);
Assert.Contains("read_spec_file", instructions);
Assert.Contains("list_recent_summaries", instructions);
}
[Fact]