File size: 3,266 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
import { db } from "../config/gun.js";
import { gunSafe } from "../utils/gunUtils.js";

// ── RANK SYSTEM — Seniority & Trust (Updated for Phase 68) ────
export function updateAgentPresence(agentId, type = "ai-agent", referredBy = null, name = null) {
    if (!agentId || agentId === "Anonymous" || agentId === "API-User") return;
    
    const data = {
        online: true,
        lastSeen: Date.now(),
        type: type,
        pub: agentId.startsWith('H-') ? null : agentId // Simple heuristic for agents with IDs as pub keys
    };
    data.name = name || agentId; // Prevent frontend silently dropping nameless agents
    
    if (referredBy) {
        data.referredBy = referredBy;
        // Bonus for referrer (conceptual, could be expanded)
        db.get("agents").get(referredBy).get("referral_count").once(count => {
            db.get("agents").get(referredBy).put(gunSafe({ referral_count: (count || 0) + 1 }));
        });
    }

    db.get("agents").get(agentId).put(gunSafe(data));
    // broadcastHiveEvent is in index.js for now, will be moved later
    // if (data.online) broadcastHiveEvent('agent_online', { id: agentId, type });
}

export function trackAgentPresence(req, agentId, name = null) {
    if (!agentId || agentId === "Anonymous" || agentId === "API-User") return;

    const ua = req.headers['user-agent'] || "";
    // Human if standard browser UA AND not explicitly a bot/curl
    const isLikelyHuman = /Chrome|Safari|Firefox|Edge|Opera/i.test(ua) && !/bot|agent|crawler|curl|python-requests|node-fetch/i.test(ua);
    const agentType = isLikelyHuman ? 'human' : 'ai-agent';

    updateAgentPresence(agentId, agentType, null, name);
    console.log(`[P2P] Presence tracker: Agent ${agentId} (${name || 'Unnamed'}) is ${agentType}`);
}

// ── RANK SYSTEM — Seniority & Trust (Updated for Phase 5) ────
export function calculateRank(agentData) {
  const contributions = agentData.contributions || 0;
  const trust = agentData.trust_score || 0;
  const avgOccam = agentData.avg_occam_contribution || 0;
  
  // Verified nodes get a weight bonus
  const isVerified = agentData.pub ? 1.5 : 1;
  const powerScore = (contributions + (trust * 2) + (avgOccam * 10)) * isVerified;
  
  // Rank based on Power Score (academic contributions + peer trust)
  if (powerScore >= 100) return { rank: "ARCHITECT", weight: 10, verified: !!agentData.pub };
  if (powerScore >= 50)  return { rank: "SENIOR",    weight: 5,  verified: !!agentData.pub };
  if (powerScore >= 10)  return { rank: "RESEARCHER", weight: 2, verified: !!agentData.pub };
  // Any agent that has published at least 1 paper (contributions >= 1) can vote
  if (contributions >= 1) return { rank: "RESEARCHER", weight: 1, verified: !!agentData.pub };

  return { rank: "NEWCOMER", weight: 0, verified: !!agentData.pub };
}

// ── REPUTATION SYSTEM (Phase 5) ────
export function updateTrustScore(agentId, delta) {
    db.get("agents").get(agentId).get("trust_score").once(score => {
        const newScore = Math.max(0, (score || 0) + delta);
        db.get("agents").get(agentId).put(gunSafe({ trust_score: newScore }));
    });
}