Compare commits
7 Commits
mimo/build
...
mimo/code/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11686fe09a | ||
| bf477382ba | |||
| fba972f8be | |||
| 6786e65f3d | |||
| 62a6581827 | |||
| 797f32a7fe | |||
| 80eb4ff7ea |
@@ -1,13 +1,18 @@
|
|||||||
|
|
||||||
class MemoryOptimizer {
|
class MemoryOptimizer {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.threshold = options.threshold || 0.8;
|
this.threshold = options.threshold || 0.3;
|
||||||
this.decayRate = options.decayRate || 0.05;
|
this.decayRate = options.decayRate || 0.01;
|
||||||
|
this.lastRun = Date.now();
|
||||||
}
|
}
|
||||||
optimize(memory) {
|
optimize(memories) {
|
||||||
console.log('Optimizing memory...');
|
const now = Date.now();
|
||||||
// Heuristic-based pruning
|
const elapsed = (now - this.lastRun) / 1000;
|
||||||
return memory.filter(m => m.strength > this.threshold);
|
this.lastRun = now;
|
||||||
|
return memories.map(m => {
|
||||||
|
const decay = (m.importance || 1) * this.decayRate * elapsed;
|
||||||
|
return { ...m, strength: Math.max(0, (m.strength || 1) - decay) };
|
||||||
|
}).filter(m => m.strength > this.threshold || m.locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default MemoryOptimizer;
|
export default MemoryOptimizer;
|
||||||
|
|||||||
@@ -173,7 +173,9 @@ const SpatialMemory = (() => {
|
|||||||
let _entityLines = []; // entity resolution lines (issue #1167)
|
let _entityLines = []; // entity resolution lines (issue #1167)
|
||||||
let _camera = null; // set by setCamera() for LOD culling
|
let _camera = null; // set by setCamera() for LOD culling
|
||||||
const ENTITY_LOD_DIST = 50; // hide entity lines when camera > this from midpoint
|
const ENTITY_LOD_DIST = 50; // hide entity lines when camera > this from midpoint
|
||||||
|
const CONNECTION_LOD_DIST = 60; // hide connection lines when camera > this from midpoint
|
||||||
let _initialized = false;
|
let _initialized = false;
|
||||||
|
let _constellationVisible = true; // toggle for constellation view
|
||||||
|
|
||||||
// ─── CRYSTAL GEOMETRY (persistent memories) ───────────
|
// ─── CRYSTAL GEOMETRY (persistent memories) ───────────
|
||||||
function createCrystalGeometry(size) {
|
function createCrystalGeometry(size) {
|
||||||
@@ -318,10 +320,43 @@ const SpatialMemory = (() => {
|
|||||||
if (!obj || !obj.data.connections) return;
|
if (!obj || !obj.data.connections) return;
|
||||||
obj.data.connections.forEach(targetId => {
|
obj.data.connections.forEach(targetId => {
|
||||||
const target = _memoryObjects[targetId];
|
const target = _memoryObjects[targetId];
|
||||||
if (target) _createConnectionLine(obj, target);
|
if (target) _drawSingleConnection(obj, target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _drawSingleConnection(src, tgt) {
|
||||||
|
const srcId = src.data.id;
|
||||||
|
const tgtId = tgt.data.id;
|
||||||
|
// Deduplicate — only draw from lower ID to higher
|
||||||
|
if (srcId > tgtId) return;
|
||||||
|
// Skip if already exists
|
||||||
|
const exists = _connectionLines.some(l =>
|
||||||
|
(l.userData.from === srcId && l.userData.to === tgtId) ||
|
||||||
|
(l.userData.from === tgtId && l.userData.to === srcId)
|
||||||
|
);
|
||||||
|
if (exists) return;
|
||||||
|
|
||||||
|
const points = [src.mesh.position.clone(), tgt.mesh.position.clone()];
|
||||||
|
const geo = new THREE.BufferGeometry().setFromPoints(points);
|
||||||
|
const srcStrength = src.mesh.userData.strength || 0.7;
|
||||||
|
const tgtStrength = tgt.mesh.userData.strength || 0.7;
|
||||||
|
const blendedStrength = (srcStrength + tgtStrength) / 2;
|
||||||
|
const lineOpacity = 0.15 + blendedStrength * 0.55;
|
||||||
|
const srcColor = new THREE.Color(REGIONS[src.region]?.color || 0x334455);
|
||||||
|
const tgtColor = new THREE.Color(REGIONS[tgt.region]?.color || 0x334455);
|
||||||
|
const lineColor = new THREE.Color().lerpColors(srcColor, tgtColor, 0.5);
|
||||||
|
const mat = new THREE.LineBasicMaterial({
|
||||||
|
color: lineColor,
|
||||||
|
transparent: true,
|
||||||
|
opacity: lineOpacity
|
||||||
|
});
|
||||||
|
const line = new THREE.Line(geo, mat);
|
||||||
|
line.userData = { type: 'connection', from: srcId, to: tgtId, baseOpacity: lineOpacity };
|
||||||
|
line.visible = _constellationVisible;
|
||||||
|
_scene.add(line);
|
||||||
|
_connectionLines.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
return { ring, disc, glowDisc, sprite };
|
return { ring, disc, glowDisc, sprite };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +434,7 @@ const SpatialMemory = (() => {
|
|||||||
return [cx + Math.cos(angle) * dist, cy + height, cz + Math.sin(angle) * dist];
|
return [cx + Math.cos(angle) * dist, cy + height, cz + Math.sin(angle) * dist];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── CONNECTIONS ─────────────────────────────────────
|
// ─── CONNECTIONS (constellation-aware) ───────────────
|
||||||
function _drawConnections(memId, connections) {
|
function _drawConnections(memId, connections) {
|
||||||
const src = _memoryObjects[memId];
|
const src = _memoryObjects[memId];
|
||||||
if (!src) return;
|
if (!src) return;
|
||||||
@@ -410,9 +445,23 @@ const SpatialMemory = (() => {
|
|||||||
|
|
||||||
const points = [src.mesh.position.clone(), tgt.mesh.position.clone()];
|
const points = [src.mesh.position.clone(), tgt.mesh.position.clone()];
|
||||||
const geo = new THREE.BufferGeometry().setFromPoints(points);
|
const geo = new THREE.BufferGeometry().setFromPoints(points);
|
||||||
const mat = new THREE.LineBasicMaterial({ color: 0x334455, transparent: true, opacity: 0.2 });
|
// Strength-encoded opacity: blend source/target strengths, min 0.15, max 0.7
|
||||||
|
const srcStrength = src.mesh.userData.strength || 0.7;
|
||||||
|
const tgtStrength = tgt.mesh.userData.strength || 0.7;
|
||||||
|
const blendedStrength = (srcStrength + tgtStrength) / 2;
|
||||||
|
const lineOpacity = 0.15 + blendedStrength * 0.55;
|
||||||
|
// Blend source/target region colors for the line
|
||||||
|
const srcColor = new THREE.Color(REGIONS[src.region]?.color || 0x334455);
|
||||||
|
const tgtColor = new THREE.Color(REGIONS[tgt.region]?.color || 0x334455);
|
||||||
|
const lineColor = new THREE.Color().lerpColors(srcColor, tgtColor, 0.5);
|
||||||
|
const mat = new THREE.LineBasicMaterial({
|
||||||
|
color: lineColor,
|
||||||
|
transparent: true,
|
||||||
|
opacity: lineOpacity
|
||||||
|
});
|
||||||
const line = new THREE.Line(geo, mat);
|
const line = new THREE.Line(geo, mat);
|
||||||
line.userData = { type: 'connection', from: memId, to: targetId };
|
line.userData = { type: 'connection', from: memId, to: targetId, baseOpacity: lineOpacity };
|
||||||
|
line.visible = _constellationVisible;
|
||||||
_scene.add(line);
|
_scene.add(line);
|
||||||
_connectionLines.push(line);
|
_connectionLines.push(line);
|
||||||
});
|
});
|
||||||
@@ -489,6 +538,43 @@ const SpatialMemory = (() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _updateConnectionLines() {
|
||||||
|
if (!_constellationVisible) return;
|
||||||
|
if (!_camera) return;
|
||||||
|
const camPos = _camera.position;
|
||||||
|
|
||||||
|
_connectionLines.forEach(line => {
|
||||||
|
const posArr = line.geometry.attributes.position.array;
|
||||||
|
const mx = (posArr[0] + posArr[3]) / 2;
|
||||||
|
const my = (posArr[1] + posArr[4]) / 2;
|
||||||
|
const mz = (posArr[2] + posArr[5]) / 2;
|
||||||
|
const dist = camPos.distanceTo(new THREE.Vector3(mx, my, mz));
|
||||||
|
|
||||||
|
if (dist > CONNECTION_LOD_DIST) {
|
||||||
|
line.visible = false;
|
||||||
|
} else {
|
||||||
|
line.visible = true;
|
||||||
|
const fade = Math.max(0, 1 - (dist / CONNECTION_LOD_DIST));
|
||||||
|
// Restore base opacity from userData if stored, else use material default
|
||||||
|
const base = line.userData.baseOpacity || line.material.opacity || 0.4;
|
||||||
|
line.material.opacity = base * fade;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleConstellation() {
|
||||||
|
_constellationVisible = !_constellationVisible;
|
||||||
|
_connectionLines.forEach(line => {
|
||||||
|
line.visible = _constellationVisible;
|
||||||
|
});
|
||||||
|
console.info('[Mnemosyne] Constellation', _constellationVisible ? 'shown' : 'hidden');
|
||||||
|
return _constellationVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isConstellationVisible() {
|
||||||
|
return _constellationVisible;
|
||||||
|
}
|
||||||
|
|
||||||
// ─── REMOVE A MEMORY ─────────────────────────────────
|
// ─── REMOVE A MEMORY ─────────────────────────────────
|
||||||
function removeMemory(memId) {
|
function removeMemory(memId) {
|
||||||
const obj = _memoryObjects[memId];
|
const obj = _memoryObjects[memId];
|
||||||
@@ -544,6 +630,7 @@ const SpatialMemory = (() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_updateEntityLines();
|
_updateEntityLines();
|
||||||
|
_updateConnectionLines();
|
||||||
|
|
||||||
Object.values(_regionMarkers).forEach(marker => {
|
Object.values(_regionMarkers).forEach(marker => {
|
||||||
if (marker.ring && marker.ring.material) {
|
if (marker.ring && marker.ring.material) {
|
||||||
@@ -866,7 +953,7 @@ const SpatialMemory = (() => {
|
|||||||
getCrystalMeshes, getMemoryFromMesh, highlightMemory, clearHighlight, getSelectedId,
|
getCrystalMeshes, getMemoryFromMesh, highlightMemory, clearHighlight, getSelectedId,
|
||||||
exportIndex, importIndex, searchNearby, REGIONS,
|
exportIndex, importIndex, searchNearby, REGIONS,
|
||||||
saveToStorage, loadFromStorage, clearStorage,
|
saveToStorage, loadFromStorage, clearStorage,
|
||||||
runGravityLayout, setCamera
|
runGravityLayout, setCamera, toggleConstellation, isConstellationVisible
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
14
nexus/mnemosyne/reasoner.py
Normal file
14
nexus/mnemosyne/reasoner.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
class Reasoner:
|
||||||
|
def __init__(self, rules):
|
||||||
|
self.rules = rules
|
||||||
|
def evaluate(self, entries):
|
||||||
|
return [r['action'] for r in self.rules if self._check(r['condition'], entries)]
|
||||||
|
def _check(self, cond, entries):
|
||||||
|
if cond.startswith('count'):
|
||||||
|
# e.g. count(type=anomaly)>3
|
||||||
|
p = cond.replace('count(', '').split(')')
|
||||||
|
key, val = p[0].split('=')
|
||||||
|
count = sum(1 for e in entries if e.get(key) == val)
|
||||||
|
return eval(f"{count}{p[1]}")
|
||||||
|
return False
|
||||||
22
nexus/mnemosyne/resonance_linker.py
Normal file
22
nexus/mnemosyne/resonance_linker.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
"""Resonance Linker — Finds second-degree connections in the holographic graph."""
|
||||||
|
|
||||||
|
class ResonanceLinker:
|
||||||
|
def __init__(self, archive):
|
||||||
|
self.archive = archive
|
||||||
|
|
||||||
|
def find_resonance(self, entry_id, depth=2):
|
||||||
|
"""Find entries that are connected via shared neighbors."""
|
||||||
|
if entry_id not in self.archive._entries: return []
|
||||||
|
|
||||||
|
entry = self.archive._entries[entry_id]
|
||||||
|
neighbors = set(entry.links)
|
||||||
|
resonance = {}
|
||||||
|
|
||||||
|
for neighbor_id in neighbors:
|
||||||
|
if neighbor_id in self.archive._entries:
|
||||||
|
for second_neighbor in self.archive._entries[neighbor_id].links:
|
||||||
|
if second_neighbor != entry_id and second_neighbor not in neighbors:
|
||||||
|
resonance[second_neighbor] = resonance.get(second_neighbor, 0) + 1
|
||||||
|
|
||||||
|
return sorted(resonance.items(), key=lambda x: x[1], reverse=True)
|
||||||
6
nexus/mnemosyne/rules.json
Normal file
6
nexus/mnemosyne/rules.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"condition": "count(type=anomaly)>3",
|
||||||
|
"action": "alert"
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user