Spaces:
Runtime error
Runtime error
| 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(); | |