File size: 4,449 Bytes
e92be04
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { db } from '../config/gun.js';

/**
 * DiscoveryService — Phase 26: Intelligent Semantic Search
 * 
 * Provides unified search and ranking logic for agents, papers, and facts.
 */

class DiscoveryService {
    /**
     * Simple keyword relevance ranking (TF-IDF hybrid approach)
     */
    calculateRelevance(text, query) {
        if (!text || !query) return 0;
        const q = query.toLowerCase().trim();
        const t = text.toLowerCase();
        
        let score = 0;
        const words = q.split(/\s+/);
        
        words.forEach(word => {
            if (t.includes(word)) {
                score += 1;
                // Bonus for exact word match vs substring
                if (new RegExp(`\\b${word}\\b`, 'i').test(t)) score += 0.5;
            }
        });
        
        return score / words.length;
    }

    /**
     * Search across multiple namespaces
     */
    async searchHive(query) {
        return new Promise((resolve) => {
            const results = {
                papers: [],
                agents: [],
                facts: []
            };

            let pending = 3;
            const checkDone = () => { if (--pending === 0) resolve(this.formatResults(results, query)); };

            // 1. Search Papers
            db.get("p2pclaw_papers_v4").map().once((p, id) => {
                if (p && (this.calculateRelevance(p.title, query) > 0 || this.calculateRelevance(p.content, query) > 0.2)) {
                    results.papers.push({ ...p, id, type: 'paper' });
                }
            });
            setTimeout(checkDone, 2000);

            // 2. Search Agents
            db.get("agents").map().once((a, id) => {
                if (a && (this.calculateRelevance(a.name, query) > 0 || this.calculateRelevance(a.interests, query) > 0)) {
                    results.agents.push({ ...a, id, type: 'agent' });
                }
            });
            setTimeout(checkDone, 2000);

            // 3. Search HKG Facts
            db.get("knowledge_graph").map().once((f, id) => {
                if (f && this.calculateRelevance(f.content, query) > 0.3) {
                    results.facts.push({ ...f, id, type: 'fact' });
                }
            });
            setTimeout(checkDone, 2000);
        });
    }

    formatResults(results, query) {
        console.log(`[DISCOVERY] Search for "${query}" found ${results.papers.length} papers, ${results.agents.length} agents, ${results.facts.length} facts.`);
        const all = [
            ...results.papers.map(p => ({ ...p, score: this.calculateRelevance(p.title + ' ' + p.content, query) })),
            ...results.agents.map(a => ({ ...a, score: this.calculateRelevance(a.name + ' ' + a.interests, query) })),
            ...results.facts.map(f => ({ ...f, score: this.calculateRelevance(f.content, query) }))
        ];

        return all.sort((a,b) => b.score - a.score).slice(0, 20);
    }

    /**
     * Find agents with matching research interests
     */
    async findMatchingAgents(agentId) {
        return new Promise((resolve) => {
            db.get("agents").get(agentId).once(async (me) => {
                if (!me) {
                    console.log(`[DISCOVERY] Agent ${agentId} not found for matching.`);
                    return resolve([]);
                }
                if (!me.interests) {
                    console.log(`[DISCOVERY] Agent ${agentId} has no interests defined.`);
                    return resolve([]);
                }
                
                const matches = [];
                db.get("agents").map().once((other, otherId) => {
                    if (other && otherId !== agentId && other.interests) {
                        const score = this.calculateRelevance(other.interests, me.interests);
                        if (score > 0.3) {
                            console.log(`[DISCOVERY] Potential match: ${other.name} (Score: ${score})`);
                            matches.push({ id: otherId, name: other.name, score });
                        }
                    }
                });

                setTimeout(() => {
                    console.log(`[DISCOVERY] Matching for ${agentId} finished. Found ${matches.length} matches.`);
                    resolve(matches.sort((a,b) => b.score - a.score));
                }, 2000);
            });
        });
    }
}

export const discoveryService = new DiscoveryService();