package copymission import ( "strings" ) type ResearchSource struct { Title string URL string Snippet string Query string } // FormatResearchItemsForMatrix renders Brave research snippets for the matrix prompt. func FormatResearchItemsForMatrix(items []ResearchSource) string { if len(items) == 0 { return "" } lines := make([]string, 0, len(items)) seen := map[string]struct{}{} for _, item := range items { title := strings.TrimSpace(item.Title) url := strings.TrimSpace(item.URL) snippet := strings.TrimSpace(item.Snippet) if title == "" && url == "" && snippet == "" { continue } key := strings.ToLower(url) if key == "" { key = strings.ToLower(title + "|" + snippet) } if _, ok := seen[key]; ok { continue } seen[key] = struct{}{} var parts []string if title != "" { parts = append(parts, title) } if url != "" { parts = append(parts, url) } if snippet != "" { parts = append(parts, snippet) } lines = append(lines, strings.Join(parts, "|")) } if len(lines) == 0 { return "" } return strings.Join(lines, "\n") } // MergeReferenceURLs combines graph-selected URLs with mission research item URLs. func MergeReferenceURLs(selected []string, researchItems []ResearchSource) []string { if len(researchItems) == 0 { return selected } out := append([]string(nil), selected...) seen := map[string]struct{}{} for _, raw := range selected { if key := normalizeURLKey(raw); key != "" { seen[key] = struct{}{} } } for _, item := range researchItems { raw := strings.TrimSpace(item.URL) key := normalizeURLKey(raw) if key == "" { continue } if _, ok := seen[key]; ok { continue } seen[key] = struct{}{} out = append(out, raw) } return out }