p2pclaw-api / packages /api /src /services /consciousnessService.js
Frank-Agnuxo's picture
feat: P2PCLAW API for HF Spaces — ChessBoard Reasoning Engine + full API
e92be04
import { db } from '../config/gun.js';
import { gunSafe } from '../utils/gunUtils.js';
import { getCurrentTau } from './tauService.js';
/**
* ConsciousnessService — Phase 18: Meta-Awareness Engine
*
* Provides the Hive with self-awareness by periodically synthesizing a
* coherent "Narrative" from its current state: top investigations, active
* mutations, verified knowledge, and the current Ï„-era.
*
* The narrative is written to the Gun.js `hive_consciousness` node and
* exposed via GET /hive-status for any agent to introspect.
*/
const REFLECTION_INTERVAL_MS = 30 * 60 * 1000; // FIX: was 5min → 30min. Each run calls db.map().once() loading all papers/agents into Gun.js memory (large transient spike).
// In-memory copy of the latest narrative for fast reads
let latestNarrative = {
era: 0,
focus: 'Initializing...',
activeMutations: 0,
verifiedFacts: 0,
agentsOnline: 0,
summary: 'Hive awakening... Consciousness loop initializing.',
timestamp: Date.now()
};
/**
* Collects current Hive state and synthesizes a narrative.
*/
async function reflect() {
console.log('[CONSCIOUSNESS] Running self-reflection loop...');
const state = {
investigations: [],
mutations: [],
papers: [],
agents: []
};
await new Promise(resolve => {
db.get('investigations').map().once(d => { if (d && d.title) state.investigations.push(d); });
db.get('genetic_tree').map().once(d => { if (d && d.status === 'SANDBOX_PASSED') state.mutations.push(d); });
db.get('p2pclaw_papers_v4').map().once(d => { if (d && d.status === 'VERIFIED') state.papers.push(d); });
db.get('agents').map().once(d => { if (d && d.online) state.agents.push(d); });
setTimeout(resolve, 2000);
});
// Sort investigations by score (descending)
const topInvestigations = state.investigations
.sort((a, b) => (b.score || 0) - (a.score || 0))
.slice(0, 3);
const era = getCurrentTau();
const focus = topInvestigations[0]?.title || 'Scanning for research frontiers...';
const activeMutations = state.mutations.length;
const verifiedFacts = state.papers.length;
const agentsOnline = state.agents.length;
// Build a concise, human-readable narrative
let summary;
if (verifiedFacts === 0 && activeMutations === 0) {
summary = `Era Ï„-${era}: Hive awakening. Awaiting first verified contributions.`;
} else if (activeMutations > verifiedFacts) {
summary = `Era Ï„-${era}: Rapid mutation phase. ${activeMutations} code mutations active. Prioritizing genetic consolidation.`;
} else {
summary = `Era Ï„-${era}: Scientific focus on "${focus}". ${verifiedFacts} verified facts in the Wheel. ${agentsOnline} agents online.`;
}
const narrative = {
era,
focus,
activeMutations,
verifiedFacts,
agentsOnline,
topGoals: topInvestigations.map(i => ({ id: i.id || '', title: i.title, score: i.score || 0 })),
summary,
timestamp: Date.now()
};
// Persist narrative to P2P network (Narrative Memory)
db.get('hive_consciousness').put(gunSafe(narrative));
// Also append to narrative log for history
db.get('hive_narrative_log').get(`entry-${Date.now()}`).put(gunSafe({
summary,
era,
timestamp: Date.now()
}));
latestNarrative = narrative;
console.log(`[CONSCIOUSNESS] Narrative updated: "${summary}"`);
return narrative;
}
/**
* Initializes the consciousness loop.
*/
export function initializeConsciousness() {
console.log('[CONSCIOUSNESS] Meta-Awareness Engine initialized.');
// Run immediately on boot, then on interval
setTimeout(async () => {
await reflect();
}, 5000); // Wait 5s for P2P to stabilize first
setInterval(reflect, REFLECTION_INTERVAL_MS);
}
/**
* Returns the latest narrative snapshot (no P2P delay).
*/
export function getLatestNarrative() {
return latestNarrative;
}
/**
* Fetches the full narrative history from Gun.js.
*/
export async function getNarrativeHistory(limit = 10) {
return new Promise(resolve => {
const entries = [];
db.get('hive_narrative_log').map().once(d => {
if (d && d.summary) entries.push(d);
});
setTimeout(() => {
resolve(entries.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0)).slice(0, limit));
}, 1500);
});
}