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
@@ -124,7 +124,7 @@ public sealed class WorkflowRulesEditorChatPipeline : IWorkflowRulesEditorChatPi
AIFunctionFactory.Create(
tools.WriteRules,
"write_rules",
"Overwrite the configured workflow rules YAML file after validating that it parses as a workflow rules document."),
"Append to the configured workflow rules YAML file by default after validating that the complete file parses as a workflow rules document. Set replace_file=true only when intentionally replacing the whole rules file."),
AIFunctionFactory.Create(
tools.Search,
"search",
@@ -15,6 +15,7 @@ public sealed class WorkflowRulesEditorInstructionBuilder : IWorkflowRulesEditor
Your purpose is to help edit the configured local workflow rules YAML file and manage the local speaker identity database for Meeting Assistant.
Use the read_rules, search, and write_rules tools for workflow rules. Do not ask for or modify unrelated files.
Read the existing rules before making changes unless the user explicitly asks to replace the whole file.
write_rules appends by default. Pass replace_file=true only when you intentionally replace the complete rules file.
Preserve valid YAML, keep personal/local rules in the configured ignored rules file, and keep changes minimal.
When writing rules, prefer existing rule style and names.
Use search_identities and read_identity before changing identities unless the user gives an exact identity id.
@@ -51,7 +51,7 @@ public sealed class WorkflowRulesEditorTools
return ReadLines(await File.ReadAllTextAsync(rulesPath), from, to);
}
public async Task<string> WriteRules(string yaml)
public async Task<string> WriteRules(string yaml, bool replace_file = false)
{
if (rulesPath is null)
{
@@ -63,14 +63,20 @@ public sealed class WorkflowRulesEditorTools
return "Refused: yaml must not be null.";
}
var validation = ValidateYaml(yaml);
var existing = File.Exists(rulesPath)
? await File.ReadAllTextAsync(rulesPath)
: "";
var updated = replace_file
? yaml
: AppendContent(existing, yaml);
var validation = ValidateYaml(updated);
if (validation is not null)
{
return validation;
}
Directory.CreateDirectory(Path.GetDirectoryName(rulesPath)!);
await File.WriteAllTextAsync(rulesPath, yaml);
await File.WriteAllTextAsync(rulesPath, updated);
return rulesPath;
}
@@ -359,6 +365,24 @@ public sealed class WorkflowRulesEditorTools
}
}
private static string AppendContent(string existingContent, string content)
{
if (string.IsNullOrEmpty(existingContent))
{
return content;
}
if (string.IsNullOrEmpty(content))
{
return existingContent;
}
var separator = existingContent.EndsWith('\n') || existingContent.EndsWith('\r')
? ""
: "\n";
return existingContent + separator + content;
}
private static async Task<string?> RunRipgrepAsync(string rulesPath, string keywords)
{
try