Seed music knowledge manuals

This commit is contained in:
Meta Vens 2026-06-01 00:22:29 +01:00
commit 16ed4084ff
6 changed files with 337 additions and 1 deletions

View file

@ -1957,6 +1957,11 @@ static IEnumerable<MusicProductionKnowledgeDocument> BuildMusicKnowledgeDocument
{
yield return curatorDocument;
}
foreach (var manualDocument in MusicManualDocuments(created))
{
yield return manualDocument;
}
}
static IEnumerable<MusicProductionKnowledgeDocument> MusicRoleDocuments(IReadOnlyList<SongSummaryRow> rendered, string created)
@ -2204,6 +2209,102 @@ static IEnumerable<MusicProductionKnowledgeDocument> MusicCuratorDocuments(strin
}
}
static IEnumerable<MusicProductionKnowledgeDocument> MusicManualDocuments(string created)
{
var manualRoot = Path.Combine(Directory.GetCurrentDirectory(), "docs", "music-production-knowledge");
if (!Directory.Exists(manualRoot))
{
yield break;
}
foreach (var manual in Directory.EnumerateFiles(manualRoot, "*.md", SearchOption.TopDirectoryOnly).Order(StringComparer.OrdinalIgnoreCase))
{
var text = ReadBoundedText(manual, 12000);
if (string.IsNullOrWhiteSpace(text))
{
continue;
}
var id = $"music-manual-{SafeName(Path.GetFileNameWithoutExtension(manual))}-{StableUuid(manual)[..8]}";
var topic = ManualField(text, "topic") ?? Path.GetFileNameWithoutExtension(manual).Replace('-', ' ');
var tier = ManualField(text, "tier") ?? "manual-doctrine";
yield return new MusicProductionKnowledgeDocument(
id,
"manual",
topic,
tier,
LinesAfterHeading(text, "Owner", 900).DefaultIfEmpty("Manual owns reusable music-production knowledge for AquaSynth agents.").First(),
text,
LinesAfterHeading(text, "Transfer Rules", 16).ToArray(),
LinesContaining(text, "meter ", "sequence ", "scale ", "chords ", "mix ", "voice ", "texture ", "source_port", "layer ", "harmonics ", "spectrum ").Take(24).ToArray(),
LinesAfterHeading(text, "Failure Modes", 16).ToArray(),
[],
[],
[new SpeechScoreMetric("manual_chars", text.Length, 0)],
[manual],
created);
}
}
static string? ManualField(string text, string field)
{
var prefix = $"{field}:";
return text.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.FirstOrDefault(line => line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))?
.Substring(prefix.Length)
.Trim();
}
static IEnumerable<string> LinesAfterHeading(string text, string heading, int maxItemsOrChars)
{
var lines = text.Split(['\r', '\n']);
var start = Array.FindIndex(lines, line => line.Trim().Equals($"## {heading}", StringComparison.OrdinalIgnoreCase));
if (start < 0)
{
yield break;
}
var collected = new List<string>();
for (var index = start + 1; index < lines.Length; index++)
{
var line = lines[index].Trim();
if (line.StartsWith("## ", StringComparison.Ordinal))
{
break;
}
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
if (line.StartsWith("- ", StringComparison.Ordinal))
{
collected.Add(line[2..].Trim());
}
else if (!line.StartsWith("```", StringComparison.Ordinal))
{
collected.Add(line);
}
}
if (maxItemsOrChars > 32)
{
var paragraph = TrimForReport(string.Join(' ', collected), maxItemsOrChars);
if (!string.IsNullOrWhiteSpace(paragraph))
{
yield return paragraph;
}
yield break;
}
foreach (var item in collected.Take(maxItemsOrChars))
{
yield return item;
}
}
static IReadOnlyList<MusicKnowledgeHit> RankMusicKnowledge(IReadOnlyList<MusicProductionKnowledgeDocument> documents, string query, int limit, string retrievalMode = "lexical")
{
var terms = ExpandTerms(Tokenize(query)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();

View file

@ -316,7 +316,7 @@ for ($pass = 1; $pass -le $Passes; $pass++) {
"--store",
$latestMusicKnowledgeStore,
"--query",
"producer brief listening journal actionable composition arrangement groove harmony melody bass drums syrinx subtractive additive pad texture mix automation failure novelty AquaSynth",
"AquaSynth DSP manual music theory production arrangement groove harmony melody bass drums syrinx subtractive additive pad texture mix automation failure novelty",
"--limit",
"40",
"--require-vector",