Make agent file writes append by default
PR and Push Build/Test / build-and-test (push) Failing after 6m36s

This commit is contained in:
2026-05-28 12:36:23 +02:00
parent 78549645bc
commit 7ff93b73b3
19 changed files with 401 additions and 27 deletions
@@ -503,12 +503,42 @@ public sealed class MeetingSummaryToolTests
""");
var tools = new MeetingSummaryTools(artifacts);
await tools.WriteContext("appended");
await tools.WriteContext("inserted", insert: 2);
await tools.WriteContext("replacement", from: 1, to: 1);
var context = await File.ReadAllTextAsync(artifacts.AssistantContextPath);
Assert.Contains("state: summarizing", context);
Assert.Contains("replacement\ninserted\nline two", context);
Assert.Contains("replacement\ninserted\nline two\nappended", context);
}
[Fact]
public async Task ToolsReplaceAssistantContextBodyOnlyWhenRequested()
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
var artifacts = new MeetingSessionArtifacts(
MeetingNotePath: Path.Combine(root, "Meetings", "Notes", "meeting.md"),
TranscriptPath: Path.Combine(root, "Meetings", "Transcripts", "transcript.md"),
AssistantContextPath: Path.Combine(root, "Meetings", "Assistant Context", "context.md"),
SummaryPath: Path.Combine(root, "Meetings", "Summaries", "summary.md"));
Directory.CreateDirectory(Path.GetDirectoryName(artifacts.AssistantContextPath)!);
await File.WriteAllTextAsync(
artifacts.AssistantContextPath,
"""
---
state: summarizing
---
line one
""");
var tools = new MeetingSummaryTools(artifacts);
await tools.WriteContext("replacement", replace_file: true);
var context = await File.ReadAllTextAsync(artifacts.AssistantContextPath);
Assert.Contains("state: summarizing", context);
Assert.Contains("replacement", context);
Assert.DoesNotContain("line one", context);
}
[Fact]
@@ -561,7 +591,8 @@ public sealed class MeetingSummaryToolTests
# Assistant Context
## Live Context
""");
""",
replace_file: true);
var context = await File.ReadAllTextAsync(artifacts.AssistantContextPath);
Assert.Contains("state: summarizing", context);
@@ -57,14 +57,14 @@ public sealed class ProjectKnowledgeToolTests
Assert.Equal("MeetingAssistant/notes/summary.md", writeResult);
Assert.Equal("# Project Update", await File.ReadAllTextAsync(Path.Combine(meetingAssistantRoot, "notes", "summary.md")));
Assert.Equal("IgnoredProject/ignored.md", await tools.WriteProjectFile("IgnoredProject", "ignored.md", "changed"));
Assert.Equal("changed", await File.ReadAllTextAsync(Path.Combine(ignoredRoot, "ignored.md")));
Assert.Equal("alpha should not be searched\nchanged", await File.ReadAllTextAsync(Path.Combine(ignoredRoot, "ignored.md")));
Assert.Equal(
"README.md:2 Second alpha line",
await tools.Search("alpha"));
}
[Fact]
public async Task WriteProjectFileSupportsOverwriteReplaceInsertAndCreate()
public async Task WriteProjectFileSupportsAppendReplaceInsertOverwriteAndCreate()
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
var projectsRoot = Path.Combine(root, "Projects");
@@ -88,6 +88,12 @@ public sealed class ProjectKnowledgeToolTests
await tools.WriteProjectFile("MeetingAssistant", "notes.md", "inserted", insert: 2);
Assert.Equal("one\ninserted\nTWO\nTHREE\nfour", await File.ReadAllTextAsync(projectFile));
await tools.WriteProjectFile("MeetingAssistant", "notes.md", "appended");
Assert.Equal("one\ninserted\nTWO\nTHREE\nfour\nappended", await File.ReadAllTextAsync(projectFile));
await tools.WriteProjectFile("MeetingAssistant", "notes.md", "replacement", replace_file: true);
Assert.Equal("replacement", await File.ReadAllTextAsync(projectFile));
await tools.WriteProjectFile("MeetingAssistant", "created/new.md", "created content");
Assert.Equal("created content", await File.ReadAllTextAsync(Path.Combine(projectRoot, "created", "new.md")));
}
@@ -112,6 +118,7 @@ public sealed class ProjectKnowledgeToolTests
Assert.StartsWith("Refused:", await tools.WriteProjectFile("MeetingAssistant", "../outside.md", "content"));
Assert.StartsWith("Refused:", await tools.WriteProjectFile("MeetingAssistant", "notes.md", "content", from: 1));
Assert.StartsWith("Refused:", await tools.WriteProjectFile("MeetingAssistant", "notes.md", "content", from: 1, to: 1, insert: 1));
Assert.StartsWith("Refused:", await tools.WriteProjectFile("MeetingAssistant", "notes.md", "content", from: 1, to: 1, replace_file: true));
}
private static MeetingSessionArtifacts CreateArtifacts(string root)
@@ -82,6 +82,46 @@ public sealed class WorkflowRulesEditorTests
Assert.DoesNotContain("other.yaml", searchResult);
}
[Fact]
public async Task RulesEditorToolsAppendByDefaultAndReplaceOnlyWhenRequested()
{
var root = Path.Combine(Path.GetTempPath(), "meeting-assistant-tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(root);
var rulesPath = Path.Combine(root, "rules.yaml");
await File.WriteAllTextAsync(
rulesPath,
"""
rules:
- name: existing
on:
- created: {}
steps:
- uses: add_attendee
value: Ada
""");
var tools = new WorkflowRulesEditorTools(new MeetingAssistantOptions
{
Automation = new AutomationOptions { RulesPath = rulesPath }
});
await tools.WriteRules("""
- name: appended
on:
- created: {}
steps:
- uses: add_attendee
value: Grace
""");
var appended = await File.ReadAllTextAsync(rulesPath);
Assert.Contains("name: existing", appended);
Assert.Contains("name: appended", appended);
await tools.WriteRules("rules: []", replace_file: true);
Assert.Equal("rules: []", await File.ReadAllTextAsync(rulesPath));
}
[Fact]
public async Task RulesEditorToolsRefuseInvalidYamlWithoutOverwritingFile()
{
@@ -94,7 +134,7 @@ public sealed class WorkflowRulesEditorTests
Automation = new AutomationOptions { RulesPath = rulesPath }
});
var result = await tools.WriteRules("rules:\n- name: [");
var result = await tools.WriteRules("rules:\n- name: [", replace_file: true);
Assert.StartsWith("Refused: workflow rules YAML is invalid.", result);
Assert.Equal("rules: []", await File.ReadAllTextAsync(rulesPath));