2263 lines
68 KiB
HTML
2263 lines
68 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>@ruvector/edge-full - Swarm Generator</title>
|
|
<style>
|
|
:root {
|
|
--bg: #0a0a0f;
|
|
--card: #12121a;
|
|
--border: #2a2a3a;
|
|
--text: #e0e0e0;
|
|
--muted: #888;
|
|
--accent: #6366f1;
|
|
--accent2: #22d3ee;
|
|
--success: #10b981;
|
|
--warning: #f59e0b;
|
|
}
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
min-height: 100vh;
|
|
padding: 20px;
|
|
}
|
|
.container { max-width: 1400px; margin: 0 auto; }
|
|
h1 {
|
|
font-size: 2rem;
|
|
background: linear-gradient(90deg, var(--accent), var(--accent2));
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
margin-bottom: 10px;
|
|
}
|
|
.subtitle { color: var(--muted); margin-bottom: 30px; }
|
|
.grid { display: grid; grid-template-columns: 350px 1fr; gap: 20px; }
|
|
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
|
|
|
|
.panel {
|
|
background: var(--card);
|
|
border: 1px solid var(--border);
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
}
|
|
.panel h2 {
|
|
font-size: 1rem;
|
|
color: var(--accent2);
|
|
margin-bottom: 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.section { margin-bottom: 20px; }
|
|
.section-title {
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
margin-bottom: 10px;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.option-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 8px;
|
|
}
|
|
.option {
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
.option:hover { border-color: var(--accent); }
|
|
.option.selected {
|
|
border-color: var(--accent);
|
|
background: rgba(99, 102, 241, 0.1);
|
|
}
|
|
.option-title { font-size: 0.85rem; font-weight: bold; }
|
|
.option-desc { font-size: 0.7rem; color: var(--muted); margin-top: 4px; }
|
|
|
|
.tag-list { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
.tag {
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
padding: 4px 10px;
|
|
font-size: 0.75rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
.tag:hover { border-color: var(--accent2); }
|
|
.tag.selected {
|
|
background: var(--accent2);
|
|
color: var(--bg);
|
|
border-color: var(--accent2);
|
|
}
|
|
|
|
.code-panel { position: relative; }
|
|
.code-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
.copy-btn {
|
|
background: var(--accent);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: 0.8rem;
|
|
}
|
|
.copy-btn:hover { opacity: 0.9; }
|
|
|
|
pre {
|
|
background: #0d0d12;
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
overflow-x: auto;
|
|
font-size: 0.8rem;
|
|
line-height: 1.6;
|
|
max-height: 600px;
|
|
overflow-y: auto;
|
|
}
|
|
code { color: var(--text); }
|
|
.keyword { color: #c792ea; }
|
|
.string { color: #c3e88d; }
|
|
.comment { color: #546e7a; }
|
|
.function { color: #82aaff; }
|
|
.number { color: #f78c6c; }
|
|
.const { color: #89ddff; }
|
|
|
|
.stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 10px;
|
|
margin-top: 20px;
|
|
}
|
|
.stat {
|
|
background: var(--bg);
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
text-align: center;
|
|
}
|
|
.stat-value {
|
|
font-size: 1.5rem;
|
|
font-weight: bold;
|
|
color: var(--accent);
|
|
}
|
|
.stat-label { font-size: 0.7rem; color: var(--muted); margin-top: 4px; }
|
|
|
|
.live-demo {
|
|
margin-top: 20px;
|
|
padding: 20px;
|
|
background: var(--bg);
|
|
border-radius: 8px;
|
|
border: 1px solid var(--border);
|
|
}
|
|
.demo-output {
|
|
font-size: 0.8rem;
|
|
color: var(--success);
|
|
white-space: pre-wrap;
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
}
|
|
.run-btn {
|
|
background: var(--success);
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: 0.85rem;
|
|
margin-bottom: 15px;
|
|
}
|
|
.run-btn:hover { opacity: 0.9; }
|
|
.run-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
|
|
.footer {
|
|
margin-top: 30px;
|
|
text-align: center;
|
|
color: var(--muted);
|
|
font-size: 0.8rem;
|
|
}
|
|
.footer a { color: var(--accent); text-decoration: none; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>@ruvector/edge-full Swarm Generator</h1>
|
|
<p class="subtitle">Generate ready-to-use code for any deployment topology</p>
|
|
|
|
<div class="grid">
|
|
<!-- Left Panel: Configuration -->
|
|
<div class="panel">
|
|
<h2>⚙️ Configuration</h2>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Topology</div>
|
|
<div class="option-grid" id="topology-options">
|
|
<div class="option selected" data-value="mesh">
|
|
<div class="option-title">🕸️ Mesh</div>
|
|
<div class="option-desc">All agents connect to all</div>
|
|
</div>
|
|
<div class="option" data-value="star">
|
|
<div class="option-title">⭐ Star</div>
|
|
<div class="option-desc">Central coordinator</div>
|
|
</div>
|
|
<div class="option" data-value="hierarchical">
|
|
<div class="option-title">🏛️ Hierarchical</div>
|
|
<div class="option-desc">Tree structure</div>
|
|
</div>
|
|
<div class="option" data-value="ring">
|
|
<div class="option-title">🔗 Ring</div>
|
|
<div class="option-desc">Circular passing</div>
|
|
</div>
|
|
<div class="option" data-value="gossip">
|
|
<div class="option-title">💬 Gossip</div>
|
|
<div class="option-desc">Epidemic broadcast</div>
|
|
</div>
|
|
<div class="option" data-value="sharded">
|
|
<div class="option-title">🧩 Sharded</div>
|
|
<div class="option-desc">Domain partitioned</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Transport</div>
|
|
<div class="option-grid" id="transport-options">
|
|
<div class="option selected" data-value="gun">
|
|
<div class="option-title">🔫 GUN.js</div>
|
|
<div class="option-desc">Free, offline-first</div>
|
|
</div>
|
|
<div class="option" data-value="webrtc">
|
|
<div class="option-title">📡 WebRTC</div>
|
|
<div class="option-desc">Direct P2P</div>
|
|
</div>
|
|
<div class="option" data-value="libp2p">
|
|
<div class="option-title">🌐 libp2p</div>
|
|
<div class="option-desc">IPFS compatible</div>
|
|
</div>
|
|
<div class="option" data-value="nostr">
|
|
<div class="option-title">⚡ Nostr</div>
|
|
<div class="option-desc">Relay-based</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Use Case</div>
|
|
<div class="option-grid" id="usecase-options">
|
|
<div class="option selected" data-value="ai-assistants">
|
|
<div class="option-title">🤖 AI Assistants</div>
|
|
<div class="option-desc">Multi-agent chat</div>
|
|
</div>
|
|
<div class="option" data-value="data-pipeline">
|
|
<div class="option-title">📊 Data Pipeline</div>
|
|
<div class="option-desc">Distributed ETL</div>
|
|
</div>
|
|
<div class="option" data-value="gaming">
|
|
<div class="option-title">🎮 Multiplayer</div>
|
|
<div class="option-desc">Real-time gaming</div>
|
|
</div>
|
|
<div class="option" data-value="iot">
|
|
<div class="option-title">📱 IoT Swarm</div>
|
|
<div class="option-desc">Edge devices</div>
|
|
</div>
|
|
<div class="option" data-value="marketplace">
|
|
<div class="option-title">🏪 Marketplace</div>
|
|
<div class="option-desc">Agent trading</div>
|
|
</div>
|
|
<div class="option" data-value="research">
|
|
<div class="option-title">🔬 Research</div>
|
|
<div class="option-desc">Distributed compute</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">WASM Modules</div>
|
|
<div class="option-grid" id="module-options">
|
|
<div class="option selected" data-value="edge">
|
|
<div class="option-title">🔐 Edge Core</div>
|
|
<div class="option-desc">364KB - Crypto, vectors</div>
|
|
</div>
|
|
<div class="option" data-value="graph">
|
|
<div class="option-title">🕸️ Graph DB</div>
|
|
<div class="option-desc">288KB - Neo4j, Cypher</div>
|
|
</div>
|
|
<div class="option" data-value="rvlite">
|
|
<div class="option-title">🗃️ RVLite</div>
|
|
<div class="option-desc">260KB - SQL/SPARQL</div>
|
|
</div>
|
|
<div class="option" data-value="sona">
|
|
<div class="option-title">🧠 SONA</div>
|
|
<div class="option-desc">238KB - LoRA, EWC++</div>
|
|
</div>
|
|
<div class="option" data-value="dag">
|
|
<div class="option-title">📊 DAG</div>
|
|
<div class="option-desc">132KB - Workflows</div>
|
|
</div>
|
|
<div class="option" data-value="onnx">
|
|
<div class="option-title">🤖 ONNX</div>
|
|
<div class="option-desc">7.1MB - Embeddings</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Features</div>
|
|
<div class="tag-list" id="feature-tags">
|
|
<div class="tag selected" data-value="identity">Identity</div>
|
|
<div class="tag selected" data-value="encryption">Encryption</div>
|
|
<div class="tag" data-value="hnsw">HNSW Index</div>
|
|
<div class="tag" data-value="semantic">Semantic Match</div>
|
|
<div class="tag" data-value="raft">Raft Consensus</div>
|
|
<div class="tag" data-value="pq">Post-Quantum</div>
|
|
<div class="tag" data-value="spiking">Spiking NN</div>
|
|
<div class="tag" data-value="compression">Compression</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Concurrency (Web Workers)</div>
|
|
<div class="option-grid" id="worker-options">
|
|
<div class="option" data-value="none">
|
|
<div class="option-title">⚡ Main Thread</div>
|
|
<div class="option-desc">Simple, no workers</div>
|
|
</div>
|
|
<div class="option selected" data-value="pool">
|
|
<div class="option-title">🔄 Worker Pool</div>
|
|
<div class="option-desc">Auto-scaling workers</div>
|
|
</div>
|
|
<div class="option" data-value="dedicated">
|
|
<div class="option-title">🎯 Dedicated</div>
|
|
<div class="option-desc">One worker per task</div>
|
|
</div>
|
|
<div class="option" data-value="shared">
|
|
<div class="option-title">🤝 Shared Worker</div>
|
|
<div class="option-desc">Cross-tab sharing</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Exotic Patterns</div>
|
|
<div class="tag-list" id="exotic-tags">
|
|
<div class="tag" data-value="mcp-browser">MCP Tools</div>
|
|
<div class="tag" data-value="byzantine">Byzantine Fault</div>
|
|
<div class="tag" data-value="quantum">Quantum Resistant</div>
|
|
<div class="tag" data-value="neural-consensus">Neural Consensus</div>
|
|
<div class="tag" data-value="swarm-intelligence">Swarm Intel</div>
|
|
<div class="tag" data-value="self-healing">Self-Healing</div>
|
|
<div class="tag" data-value="emergent">Emergent Behavior</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stats">
|
|
<div class="stat">
|
|
<div class="stat-value" id="agent-count">3</div>
|
|
<div class="stat-label">Agents</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-value" id="worker-count">4</div>
|
|
<div class="stat-label">Workers</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-value">$0</div>
|
|
<div class="stat-label">Monthly</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div class="stat-value" id="bundle-size">364KB</div>
|
|
<div class="stat-label">Bundle</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Panel: Generated Code -->
|
|
<div class="panel code-panel">
|
|
<div class="code-header">
|
|
<h2>📄 Generated Code</h2>
|
|
<button class="copy-btn" onclick="copyCode()">📋 Copy Code</button>
|
|
</div>
|
|
<pre><code id="generated-code"></code></pre>
|
|
|
|
<div class="live-demo">
|
|
<button class="run-btn" id="run-btn" onclick="runDemo()">▶️ Run Live Demo</button>
|
|
<div class="demo-output" id="demo-output">Click "Run Live Demo" to execute in browser...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<p>
|
|
<a href="https://www.npmjs.com/package/@ruvector/edge">npm</a> •
|
|
<a href="https://github.com/ruvnet/ruvector">GitHub</a> •
|
|
MIT License • $0 Forever
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import init, {
|
|
WasmIdentity,
|
|
WasmCrypto,
|
|
WasmHnswIndex,
|
|
WasmSemanticMatcher,
|
|
WasmRaftNode,
|
|
WasmHybridKeyPair,
|
|
WasmSpikingNetwork,
|
|
WasmQuantizer,
|
|
WasmAdaptiveCompressor
|
|
} from './ruvector_edge.js';
|
|
|
|
let wasmReady = false;
|
|
|
|
// Initialize WASM
|
|
init().then(() => {
|
|
wasmReady = true;
|
|
document.getElementById('run-btn').disabled = false;
|
|
console.log('@ruvector/edge WASM loaded');
|
|
}).catch(err => {
|
|
console.error('WASM load failed:', err);
|
|
});
|
|
|
|
// State
|
|
const state = {
|
|
topology: 'mesh',
|
|
transport: 'gun',
|
|
usecase: 'ai-assistants',
|
|
modules: ['edge'],
|
|
features: ['identity', 'encryption'],
|
|
workers: 'pool',
|
|
exotic: []
|
|
};
|
|
|
|
// Module sizes in KB
|
|
const moduleSizes = {
|
|
edge: 364,
|
|
graph: 288,
|
|
rvlite: 260,
|
|
sona: 238,
|
|
dag: 132,
|
|
onnx: 7270 // 7.1MB
|
|
};
|
|
|
|
function updateBundleSize() {
|
|
const totalKB = state.modules.reduce((sum, mod) => sum + moduleSizes[mod], 0);
|
|
const sizeStr = totalKB >= 1024 ? `${(totalKB / 1024).toFixed(1)}MB` : `${totalKB}KB`;
|
|
document.getElementById('bundle-size').textContent = sizeStr;
|
|
}
|
|
|
|
// Code templates
|
|
const templates = {
|
|
// Topology patterns
|
|
topologies: {
|
|
mesh: `// Mesh Topology - All agents connected to all
|
|
class MeshSwarm {
|
|
constructor() {
|
|
this.agents = new Map();
|
|
this.matcher = new WasmSemanticMatcher();
|
|
}
|
|
|
|
addAgent(id, capabilities) {
|
|
const identity = WasmIdentity.generate();
|
|
this.agents.set(id, { identity, capabilities });
|
|
this.matcher.register_agent(id, capabilities);
|
|
|
|
// Notify all existing agents
|
|
this.broadcast({ type: 'agent_joined', id, capabilities });
|
|
}
|
|
|
|
broadcast(message) {
|
|
for (const [id, agent] of this.agents) {
|
|
this.sendTo(id, message);
|
|
}
|
|
}
|
|
|
|
routeTask(task) {
|
|
return this.matcher.find_best_agent(task);
|
|
}
|
|
}`,
|
|
|
|
star: `// Star Topology - Central coordinator
|
|
class StarSwarm {
|
|
constructor() {
|
|
this.coordinator = WasmIdentity.generate();
|
|
this.workers = new Map();
|
|
this.raft = null;
|
|
}
|
|
|
|
initCoordinator(workerIds) {
|
|
this.raft = new WasmRaftNode('coordinator', ['coordinator', ...workerIds]);
|
|
this.raft.start_election();
|
|
}
|
|
|
|
addWorker(id, capabilities) {
|
|
const identity = WasmIdentity.generate();
|
|
this.workers.set(id, { identity, capabilities });
|
|
// Worker only connects to coordinator
|
|
}
|
|
|
|
dispatch(task) {
|
|
// Coordinator routes all tasks
|
|
const workers = Array.from(this.workers.keys());
|
|
return workers[Math.floor(Math.random() * workers.length)];
|
|
}
|
|
}`,
|
|
|
|
hierarchical: `// Hierarchical Topology - Tree structure
|
|
class HierarchicalSwarm {
|
|
constructor(levels = 3) {
|
|
this.levels = levels;
|
|
this.tree = this.buildTree(levels);
|
|
}
|
|
|
|
buildTree(depth, prefix = 'node') {
|
|
if (depth === 0) return null;
|
|
return {
|
|
id: prefix,
|
|
identity: WasmIdentity.generate(),
|
|
children: depth > 1 ? [
|
|
this.buildTree(depth - 1, \`\${prefix}-L\`),
|
|
this.buildTree(depth - 1, \`\${prefix}-R\`)
|
|
] : []
|
|
};
|
|
}
|
|
|
|
propagateDown(node, message) {
|
|
if (!node) return;
|
|
console.log(\`\${node.id} received:\`, message);
|
|
node.children.forEach(child => this.propagateDown(child, message));
|
|
}
|
|
|
|
aggregateUp(node, fn) {
|
|
if (!node.children.length) return fn(node);
|
|
const childResults = node.children.map(c => this.aggregateUp(c, fn));
|
|
return fn(node, childResults);
|
|
}
|
|
}`,
|
|
|
|
ring: `// Ring Topology - Circular message passing
|
|
class RingSwarm {
|
|
constructor(size = 5) {
|
|
this.ring = [];
|
|
for (let i = 0; i < size; i++) {
|
|
this.ring.push({
|
|
id: \`node-\${i}\`,
|
|
identity: WasmIdentity.generate(),
|
|
next: null
|
|
});
|
|
}
|
|
// Connect ring
|
|
for (let i = 0; i < size; i++) {
|
|
this.ring[i].next = this.ring[(i + 1) % size];
|
|
}
|
|
}
|
|
|
|
passMessage(startIdx, message, hops = this.ring.length) {
|
|
let current = this.ring[startIdx];
|
|
for (let i = 0; i < hops; i++) {
|
|
console.log(\`\${current.id} processing:\`, message);
|
|
message = this.transform(current, message);
|
|
current = current.next;
|
|
}
|
|
return message;
|
|
}
|
|
|
|
transform(node, message) {
|
|
return { ...message, visited: [...(message.visited || []), node.id] };
|
|
}
|
|
}`,
|
|
|
|
gossip: `// Gossip Protocol - Epidemic broadcast
|
|
class GossipSwarm {
|
|
constructor(fanout = 3) {
|
|
this.fanout = fanout;
|
|
this.nodes = new Map();
|
|
this.seen = new Set();
|
|
}
|
|
|
|
addNode(id) {
|
|
this.nodes.set(id, {
|
|
identity: WasmIdentity.generate(),
|
|
data: new Map()
|
|
});
|
|
}
|
|
|
|
gossip(fromId, key, value) {
|
|
const msgId = \`\${key}-\${Date.now()}\`;
|
|
if (this.seen.has(msgId)) return;
|
|
this.seen.add(msgId);
|
|
|
|
// Update local
|
|
this.nodes.get(fromId).data.set(key, value);
|
|
|
|
// Spread to random peers
|
|
const peers = Array.from(this.nodes.keys()).filter(id => id !== fromId);
|
|
const selected = this.selectRandom(peers, this.fanout);
|
|
|
|
selected.forEach(peerId => {
|
|
setTimeout(() => this.gossip(peerId, key, value), Math.random() * 100);
|
|
});
|
|
}
|
|
|
|
selectRandom(arr, n) {
|
|
return arr.sort(() => Math.random() - 0.5).slice(0, n);
|
|
}
|
|
}`,
|
|
|
|
sharded: `// Sharded Topology - Domain partitioned
|
|
class ShardedSwarm {
|
|
constructor(shardCount = 4) {
|
|
this.shards = new Map();
|
|
for (let i = 0; i < shardCount; i++) {
|
|
this.shards.set(i, {
|
|
id: \`shard-\${i}\`,
|
|
agents: new Map(),
|
|
index: new WasmHnswIndex(128, 16, 200)
|
|
});
|
|
}
|
|
}
|
|
|
|
getShard(key) {
|
|
const hash = this.hash(key);
|
|
return this.shards.get(hash % this.shards.size);
|
|
}
|
|
|
|
hash(str) {
|
|
let hash = 0;
|
|
for (let i = 0; i < str.length; i++) {
|
|
hash = ((hash << 5) - hash) + str.charCodeAt(i);
|
|
}
|
|
return Math.abs(hash);
|
|
}
|
|
|
|
addAgent(domain, id, embedding) {
|
|
const shard = this.getShard(domain);
|
|
shard.agents.set(id, WasmIdentity.generate());
|
|
shard.index.insert(id, embedding);
|
|
}
|
|
|
|
query(domain, embedding, k = 5) {
|
|
const shard = this.getShard(domain);
|
|
return shard.index.search(embedding, k);
|
|
}
|
|
}`
|
|
},
|
|
|
|
// Transport implementations
|
|
transports: {
|
|
gun: `// GUN.js Transport - Free, offline-first
|
|
import Gun from 'gun';
|
|
|
|
const gun = Gun([
|
|
'https://gun-manhattan.herokuapp.com/gun',
|
|
'https://gun-us.herokuapp.com/gun'
|
|
]);
|
|
|
|
const swarm = gun.get('my-ai-swarm');
|
|
|
|
// Publish agent
|
|
function announce(agent) {
|
|
swarm.get('agents').get(agent.id).put({
|
|
id: agent.id,
|
|
publicKey: agent.identity.public_key_hex(),
|
|
capabilities: agent.capabilities,
|
|
online: true,
|
|
timestamp: Date.now()
|
|
});
|
|
}
|
|
|
|
// Subscribe to agents
|
|
swarm.get('agents').map().on((data, id) => {
|
|
if (data) console.log('Agent update:', id, data);
|
|
});
|
|
|
|
// Send task
|
|
function sendTask(task) {
|
|
swarm.get('tasks').set({
|
|
id: crypto.randomUUID(),
|
|
...task,
|
|
timestamp: Date.now()
|
|
});
|
|
}`,
|
|
|
|
webrtc: `// WebRTC Transport - Direct P2P
|
|
const rtcConfig = {
|
|
iceServers: [
|
|
{ urls: 'stun:stun.l.google.com:19302' },
|
|
{ urls: 'stun:stun.cloudflare.com:3478' }
|
|
]
|
|
};
|
|
|
|
class WebRTCTransport {
|
|
constructor() {
|
|
this.peers = new Map();
|
|
this.crypto = new WasmCrypto();
|
|
}
|
|
|
|
async connect(peerId, signalChannel) {
|
|
const pc = new RTCPeerConnection(rtcConfig);
|
|
const channel = pc.createDataChannel('swarm');
|
|
|
|
channel.onopen = () => {
|
|
console.log(\`Connected to \${peerId}\`);
|
|
this.peers.set(peerId, { pc, channel });
|
|
};
|
|
|
|
channel.onmessage = (e) => this.handleMessage(peerId, e.data);
|
|
|
|
const offer = await pc.createOffer();
|
|
await pc.setLocalDescription(offer);
|
|
signalChannel.send({ type: 'offer', peerId, offer });
|
|
}
|
|
|
|
send(peerId, message) {
|
|
const peer = this.peers.get(peerId);
|
|
if (peer?.channel?.readyState === 'open') {
|
|
const key = this.getSharedKey(peerId);
|
|
const encrypted = this.crypto.encrypt(key,
|
|
new TextEncoder().encode(JSON.stringify(message)));
|
|
peer.channel.send(encrypted);
|
|
}
|
|
}
|
|
}`,
|
|
|
|
libp2p: `// libp2p Transport - IPFS compatible
|
|
import { createLibp2p } from 'libp2p';
|
|
import { webSockets } from '@libp2p/websockets';
|
|
import { noise } from '@chainsafe/libp2p-noise';
|
|
import { gossipsub } from '@chainsafe/libp2p-gossipsub';
|
|
import { kadDHT } from '@libp2p/kad-dht';
|
|
|
|
async function createNode() {
|
|
const node = await createLibp2p({
|
|
transports: [webSockets()],
|
|
connectionEncryption: [noise()],
|
|
pubsub: gossipsub(),
|
|
dht: kadDHT()
|
|
});
|
|
|
|
await node.start();
|
|
return node;
|
|
}
|
|
|
|
class Libp2pTransport {
|
|
constructor(node) {
|
|
this.node = node;
|
|
this.topic = 'ruvector-swarm';
|
|
}
|
|
|
|
async subscribe(handler) {
|
|
this.node.pubsub.subscribe(this.topic);
|
|
this.node.pubsub.addEventListener('message', (evt) => {
|
|
if (evt.detail.topic === this.topic) {
|
|
const msg = JSON.parse(new TextDecoder().decode(evt.detail.data));
|
|
handler(msg);
|
|
}
|
|
});
|
|
}
|
|
|
|
async publish(message) {
|
|
await this.node.pubsub.publish(
|
|
this.topic,
|
|
new TextEncoder().encode(JSON.stringify(message))
|
|
);
|
|
}
|
|
}`,
|
|
|
|
nostr: `// Nostr Transport - Relay-based
|
|
import { relayInit, generatePrivateKey, getPublicKey } from 'nostr-tools';
|
|
|
|
const RELAYS = [
|
|
'wss://relay.damus.io',
|
|
'wss://nos.lol',
|
|
'wss://relay.nostr.band'
|
|
];
|
|
|
|
class NostrTransport {
|
|
constructor() {
|
|
this.relays = [];
|
|
this.sk = generatePrivateKey();
|
|
this.pk = getPublicKey(this.sk);
|
|
}
|
|
|
|
async connect() {
|
|
for (const url of RELAYS) {
|
|
const relay = relayInit(url);
|
|
await relay.connect();
|
|
this.relays.push(relay);
|
|
}
|
|
}
|
|
|
|
subscribe(swarmId, handler) {
|
|
this.relays.forEach(relay => {
|
|
const sub = relay.sub([
|
|
{ kinds: [29000], '#swarm': [swarmId] }
|
|
]);
|
|
sub.on('event', handler);
|
|
});
|
|
}
|
|
|
|
async publish(swarmId, content) {
|
|
const event = {
|
|
kind: 29000,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [['swarm', swarmId]],
|
|
content: JSON.stringify(content),
|
|
pubkey: this.pk
|
|
};
|
|
// Sign and publish to all relays
|
|
for (const relay of this.relays) {
|
|
await relay.publish(event);
|
|
}
|
|
}
|
|
}`
|
|
},
|
|
|
|
// Use case implementations
|
|
usecases: {
|
|
'ai-assistants': `// AI Assistant Swarm - Multi-agent chat
|
|
class AIAssistantSwarm {
|
|
constructor() {
|
|
this.agents = new Map();
|
|
this.matcher = new WasmSemanticMatcher();
|
|
this.history = [];
|
|
}
|
|
|
|
registerAssistant(id, specialty) {
|
|
const identity = WasmIdentity.generate();
|
|
this.agents.set(id, { identity, specialty });
|
|
this.matcher.register_agent(id, specialty);
|
|
}
|
|
|
|
async chat(userMessage) {
|
|
// Route to best agent
|
|
const bestAgent = this.matcher.find_best_agent(userMessage);
|
|
const agent = this.agents.get(bestAgent);
|
|
|
|
console.log(\`Routing to \${bestAgent}: \${userMessage}\`);
|
|
|
|
// Record in history
|
|
this.history.push({
|
|
role: 'user',
|
|
content: userMessage,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
// Agent processes (would call LLM API here)
|
|
const response = await this.processWithAgent(agent, userMessage);
|
|
|
|
this.history.push({
|
|
role: bestAgent,
|
|
content: response,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
return { agent: bestAgent, response };
|
|
}
|
|
}
|
|
|
|
// Example
|
|
const swarm = new AIAssistantSwarm();
|
|
swarm.registerAssistant('coder', 'programming code typescript rust python');
|
|
swarm.registerAssistant('writer', 'writing documentation blog articles');
|
|
swarm.registerAssistant('analyst', 'data analysis statistics charts');`,
|
|
|
|
'data-pipeline': `// Distributed Data Pipeline - ETL Swarm
|
|
class DataPipelineSwarm {
|
|
constructor() {
|
|
this.stages = new Map();
|
|
this.compressor = new WasmAdaptiveCompressor();
|
|
}
|
|
|
|
addStage(name, processFn) {
|
|
this.stages.set(name, {
|
|
identity: WasmIdentity.generate(),
|
|
process: processFn,
|
|
metrics: { processed: 0, errors: 0 }
|
|
});
|
|
}
|
|
|
|
async run(data, pipeline) {
|
|
let current = data;
|
|
|
|
for (const stageName of pipeline) {
|
|
const stage = this.stages.get(stageName);
|
|
console.log(\`Stage \${stageName}: processing \${current.length} items\`);
|
|
|
|
try {
|
|
current = await stage.process(current);
|
|
stage.metrics.processed += current.length;
|
|
} catch (err) {
|
|
stage.metrics.errors++;
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
}
|
|
|
|
// Example pipeline
|
|
const pipeline = new DataPipelineSwarm();
|
|
pipeline.addStage('extract', (data) => data.map(d => d.raw));
|
|
pipeline.addStage('transform', (data) => data.filter(d => d.valid));
|
|
pipeline.addStage('load', (data) => { console.log('Loaded:', data.length); return data; });`,
|
|
|
|
gaming: `// Multiplayer Game Swarm - Real-time sync
|
|
class GameSwarm {
|
|
constructor() {
|
|
this.players = new Map();
|
|
this.raft = null;
|
|
this.gameState = { entities: [], tick: 0 };
|
|
}
|
|
|
|
initLobby(playerIds) {
|
|
this.raft = new WasmRaftNode(playerIds[0], playerIds);
|
|
playerIds.forEach(id => {
|
|
this.players.set(id, {
|
|
identity: WasmIdentity.generate(),
|
|
position: { x: 0, y: 0 },
|
|
score: 0
|
|
});
|
|
});
|
|
}
|
|
|
|
electHost() {
|
|
this.raft.start_election();
|
|
// Simulate votes
|
|
this.raft.receive_vote(true);
|
|
this.raft.receive_vote(true);
|
|
return this.raft.state() === 'leader';
|
|
}
|
|
|
|
updatePlayer(playerId, action) {
|
|
const player = this.players.get(playerId);
|
|
const signed = player.identity.sign(
|
|
new TextEncoder().encode(JSON.stringify(action))
|
|
);
|
|
|
|
// Apply action
|
|
if (action.type === 'move') {
|
|
player.position.x += action.dx;
|
|
player.position.y += action.dy;
|
|
}
|
|
|
|
this.gameState.tick++;
|
|
return this.gameState;
|
|
}
|
|
}`,
|
|
|
|
iot: `// IoT Swarm - Edge device coordination
|
|
class IoTSwarm {
|
|
constructor() {
|
|
this.devices = new Map();
|
|
this.index = new WasmHnswIndex(64, 8, 100);
|
|
this.quantizer = new WasmQuantizer();
|
|
}
|
|
|
|
registerDevice(id, type, location) {
|
|
const identity = WasmIdentity.generate();
|
|
const embedding = this.createEmbedding(type, location);
|
|
|
|
this.devices.set(id, { identity, type, location, lastSeen: Date.now() });
|
|
this.index.insert(id, embedding);
|
|
}
|
|
|
|
createEmbedding(type, location) {
|
|
const vec = new Float32Array(64);
|
|
vec[0] = location.lat / 90;
|
|
vec[1] = location.lng / 180;
|
|
vec[2] = type === 'sensor' ? 1 : 0;
|
|
vec[3] = type === 'actuator' ? 1 : 0;
|
|
return vec;
|
|
}
|
|
|
|
findNearbyDevices(location, k = 5) {
|
|
const query = this.createEmbedding('query', location);
|
|
return this.index.search(query, k);
|
|
}
|
|
|
|
broadcastToRegion(location, radius, command) {
|
|
const nearby = this.findNearbyDevices(location, 20);
|
|
nearby.forEach(([id, distance]) => {
|
|
if (distance < radius) {
|
|
console.log(\`Command to \${id}: \${command}\`);
|
|
}
|
|
});
|
|
}
|
|
}`,
|
|
|
|
marketplace: `// Agent Marketplace - Trading swarm
|
|
class MarketplaceSwarm {
|
|
constructor() {
|
|
this.agents = new Map();
|
|
this.orderBook = { bids: [], asks: [] };
|
|
this.matcher = new WasmSemanticMatcher();
|
|
}
|
|
|
|
registerTrader(id, specialties) {
|
|
const identity = WasmIdentity.generate();
|
|
this.agents.set(id, {
|
|
identity,
|
|
balance: 1000,
|
|
holdings: new Map()
|
|
});
|
|
this.matcher.register_agent(id, specialties);
|
|
}
|
|
|
|
submitOrder(agentId, type, asset, price, quantity) {
|
|
const agent = this.agents.get(agentId);
|
|
const order = {
|
|
id: crypto.randomUUID(),
|
|
agentId,
|
|
type,
|
|
asset,
|
|
price,
|
|
quantity,
|
|
signature: agent.identity.sign(
|
|
new TextEncoder().encode(\`\${type}:\${asset}:\${price}:\${quantity}\`)
|
|
),
|
|
timestamp: Date.now()
|
|
};
|
|
|
|
if (type === 'bid') this.orderBook.bids.push(order);
|
|
else this.orderBook.asks.push(order);
|
|
|
|
return this.matchOrders(asset);
|
|
}
|
|
|
|
matchOrders(asset) {
|
|
// Simple matching logic
|
|
const bids = this.orderBook.bids.filter(o => o.asset === asset);
|
|
const asks = this.orderBook.asks.filter(o => o.asset === asset);
|
|
|
|
bids.sort((a, b) => b.price - a.price);
|
|
asks.sort((a, b) => a.price - b.price);
|
|
|
|
const trades = [];
|
|
// Match orders...
|
|
return trades;
|
|
}
|
|
}`,
|
|
|
|
research: `// Distributed Research Swarm - Compute grid
|
|
class ResearchSwarm {
|
|
constructor() {
|
|
this.workers = new Map();
|
|
this.tasks = [];
|
|
this.results = new Map();
|
|
this.network = new WasmSpikingNetwork(10, 20, 5);
|
|
}
|
|
|
|
addWorker(id, capabilities) {
|
|
this.workers.set(id, {
|
|
identity: WasmIdentity.generate(),
|
|
capabilities,
|
|
busy: false,
|
|
completed: 0
|
|
});
|
|
}
|
|
|
|
submitTask(task) {
|
|
const taskId = crypto.randomUUID();
|
|
this.tasks.push({ id: taskId, ...task, status: 'pending' });
|
|
return taskId;
|
|
}
|
|
|
|
schedule() {
|
|
for (const task of this.tasks.filter(t => t.status === 'pending')) {
|
|
// Find available worker
|
|
const available = Array.from(this.workers.entries())
|
|
.filter(([_, w]) => !w.busy);
|
|
|
|
if (available.length > 0) {
|
|
const [workerId, worker] = available[0];
|
|
worker.busy = true;
|
|
task.status = 'running';
|
|
task.worker = workerId;
|
|
|
|
console.log(\`Assigned \${task.id} to \${workerId}\`);
|
|
}
|
|
}
|
|
}
|
|
|
|
aggregateResults(taskIds) {
|
|
// Use spiking network for result fusion
|
|
const inputs = taskIds.map(id => this.results.has(id));
|
|
return this.network.forward(inputs);
|
|
}
|
|
}`
|
|
},
|
|
|
|
// Exotic patterns
|
|
exotic: {
|
|
byzantine: `// Byzantine Fault Tolerance
|
|
class ByzantineSwarm {
|
|
constructor(n) {
|
|
this.n = n;
|
|
this.f = Math.floor((n - 1) / 3); // Max faulty nodes
|
|
this.nodes = [];
|
|
|
|
for (let i = 0; i < n; i++) {
|
|
this.nodes.push({
|
|
id: i,
|
|
identity: WasmIdentity.generate(),
|
|
honest: Math.random() > 0.1 // 10% faulty
|
|
});
|
|
}
|
|
}
|
|
|
|
byzantineAgreement(value) {
|
|
const votes = new Map();
|
|
|
|
// Each node broadcasts
|
|
for (const node of this.nodes) {
|
|
const vote = node.honest ? value : Math.random() > 0.5;
|
|
const signed = node.identity.sign(
|
|
new TextEncoder().encode(String(vote))
|
|
);
|
|
votes.set(node.id, { vote, signed });
|
|
}
|
|
|
|
// Tally
|
|
const trueVotes = Array.from(votes.values()).filter(v => v.vote).length;
|
|
return trueVotes > this.n - this.f;
|
|
}
|
|
}`,
|
|
|
|
quantum: `// Quantum-Resistant Swarm
|
|
class QuantumResistantSwarm {
|
|
constructor() {
|
|
this.agents = new Map();
|
|
}
|
|
|
|
addAgent(id) {
|
|
// Use post-quantum hybrid signatures
|
|
const hybridKey = WasmHybridKeyPair.generate();
|
|
this.agents.set(id, { hybridKey });
|
|
}
|
|
|
|
signMessage(agentId, message) {
|
|
const agent = this.agents.get(agentId);
|
|
// Hybrid signature: Ed25519 + Dilithium-style
|
|
return agent.hybridKey.sign(message);
|
|
}
|
|
|
|
verifyMessage(agentId, message, signature) {
|
|
const agent = this.agents.get(agentId);
|
|
return agent.hybridKey.verify(message, signature);
|
|
}
|
|
}`,
|
|
|
|
'neural-consensus': `// Neural Consensus - Spiking network voting
|
|
class NeuralConsensus {
|
|
constructor(numVoters) {
|
|
this.network = new WasmSpikingNetwork(numVoters, numVoters * 2, 1);
|
|
this.voters = [];
|
|
|
|
for (let i = 0; i < numVoters; i++) {
|
|
this.voters.push(WasmIdentity.generate());
|
|
}
|
|
}
|
|
|
|
vote(opinions) {
|
|
// Convert opinions to spikes
|
|
const spikes = opinions.map(o => o > 0.5);
|
|
|
|
// Process through spiking network
|
|
const output = this.network.forward(spikes);
|
|
|
|
// STDP learning from consensus
|
|
this.network.stdp_update(spikes, output, 0.01);
|
|
|
|
return output[0]; // Consensus decision
|
|
}
|
|
}`,
|
|
|
|
'swarm-intelligence': `// Swarm Intelligence - Emergent optimization
|
|
class SwarmIntelligence {
|
|
constructor(particleCount = 50) {
|
|
this.particles = [];
|
|
this.globalBest = null;
|
|
this.globalBestScore = -Infinity;
|
|
|
|
for (let i = 0; i < particleCount; i++) {
|
|
this.particles.push({
|
|
identity: WasmIdentity.generate(),
|
|
position: Array(10).fill(0).map(() => Math.random()),
|
|
velocity: Array(10).fill(0).map(() => (Math.random() - 0.5) * 0.1),
|
|
bestPosition: null,
|
|
bestScore: -Infinity
|
|
});
|
|
}
|
|
}
|
|
|
|
optimize(fitnessFunction, iterations = 100) {
|
|
for (let i = 0; i < iterations; i++) {
|
|
for (const particle of this.particles) {
|
|
const score = fitnessFunction(particle.position);
|
|
|
|
if (score > particle.bestScore) {
|
|
particle.bestScore = score;
|
|
particle.bestPosition = [...particle.position];
|
|
}
|
|
|
|
if (score > this.globalBestScore) {
|
|
this.globalBestScore = score;
|
|
this.globalBest = [...particle.position];
|
|
}
|
|
|
|
// Update velocity and position
|
|
this.updateParticle(particle);
|
|
}
|
|
}
|
|
|
|
return { position: this.globalBest, score: this.globalBestScore };
|
|
}
|
|
|
|
updateParticle(particle) {
|
|
const w = 0.7, c1 = 1.5, c2 = 1.5;
|
|
for (let d = 0; d < particle.position.length; d++) {
|
|
particle.velocity[d] =
|
|
w * particle.velocity[d] +
|
|
c1 * Math.random() * (particle.bestPosition[d] - particle.position[d]) +
|
|
c2 * Math.random() * (this.globalBest[d] - particle.position[d]);
|
|
particle.position[d] += particle.velocity[d];
|
|
}
|
|
}
|
|
}`,
|
|
|
|
'mcp-browser': `// Browser-Based MCP Tools - Collaborative AI
|
|
class BrowserMCPServer {
|
|
constructor() {
|
|
this.tools = new Map();
|
|
this.resources = new Map();
|
|
this.identity = null;
|
|
this.peers = new Map();
|
|
}
|
|
|
|
async init() {
|
|
await init();
|
|
this.identity = WasmIdentity.generate();
|
|
this.crypto = new WasmCrypto();
|
|
this.index = new WasmHnswIndex(128, 16, 200);
|
|
this.matcher = new WasmSemanticMatcher();
|
|
|
|
// Register built-in tools
|
|
this.registerBuiltinTools();
|
|
}
|
|
|
|
registerBuiltinTools() {
|
|
// Agent discovery tool
|
|
this.registerTool('discover_agents', {
|
|
description: 'Find agents with specific capabilities',
|
|
schema: { type: 'object', properties: { query: { type: 'string' } } },
|
|
handler: async ({ query }) => {
|
|
return this.matcher.find_best_agent(query);
|
|
}
|
|
});
|
|
|
|
// Secure message tool
|
|
this.registerTool('send_secure_message', {
|
|
description: 'Send encrypted message to peer',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
peerId: { type: 'string' },
|
|
message: { type: 'string' }
|
|
}
|
|
},
|
|
handler: async ({ peerId, message }) => {
|
|
const peer = this.peers.get(peerId);
|
|
if (!peer) throw new Error('Peer not found');
|
|
|
|
const encrypted = this.crypto.encrypt(
|
|
peer.sharedKey,
|
|
new TextEncoder().encode(message)
|
|
);
|
|
return { encrypted: Array.from(encrypted), size: encrypted.length };
|
|
}
|
|
});
|
|
|
|
// Vector memory tool
|
|
this.registerTool('store_memory', {
|
|
description: 'Store vector in distributed memory',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
key: { type: 'string' },
|
|
embedding: { type: 'array', items: { type: 'number' } }
|
|
}
|
|
},
|
|
handler: async ({ key, embedding }) => {
|
|
this.index.insert(key, new Float32Array(embedding));
|
|
return { stored: key, total: this.index.len() };
|
|
}
|
|
});
|
|
|
|
// Semantic search tool
|
|
this.registerTool('search_memory', {
|
|
description: 'Search vector memory',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: { type: 'array', items: { type: 'number' } },
|
|
k: { type: 'number', default: 5 }
|
|
}
|
|
},
|
|
handler: async ({ query, k = 5 }) => {
|
|
return this.index.search(new Float32Array(query), k);
|
|
}
|
|
});
|
|
|
|
// Sign message tool
|
|
this.registerTool('sign_message', {
|
|
description: 'Cryptographically sign a message',
|
|
schema: { type: 'object', properties: { message: { type: 'string' } } },
|
|
handler: async ({ message }) => {
|
|
const sig = this.identity.sign(new TextEncoder().encode(message));
|
|
return { signature: Array.from(sig), agentId: this.identity.agent_id() };
|
|
}
|
|
});
|
|
}
|
|
|
|
registerTool(name, { description, schema, handler }) {
|
|
this.tools.set(name, { description, schema, handler });
|
|
this.matcher.register_agent(name, description);
|
|
}
|
|
|
|
async handleRequest(request) {
|
|
const { method, params } = request;
|
|
|
|
switch (method) {
|
|
case 'tools/list':
|
|
return {
|
|
tools: Array.from(this.tools.entries()).map(([name, tool]) => ({
|
|
name,
|
|
description: tool.description,
|
|
inputSchema: tool.schema
|
|
}))
|
|
};
|
|
|
|
case 'tools/call':
|
|
const tool = this.tools.get(params.name);
|
|
if (!tool) throw new Error(\`Unknown tool: \${params.name}\`);
|
|
return { content: [{ type: 'text', text: JSON.stringify(await tool.handler(params.arguments)) }] };
|
|
|
|
case 'resources/list':
|
|
return { resources: Array.from(this.resources.keys()) };
|
|
|
|
default:
|
|
throw new Error(\`Unknown method: \${method}\`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Collaborative MCP Network
|
|
class MCPCollaborativeNetwork {
|
|
constructor() {
|
|
this.servers = new Map();
|
|
this.raft = null;
|
|
}
|
|
|
|
async addServer(id, capabilities) {
|
|
const server = new BrowserMCPServer();
|
|
await server.init();
|
|
this.servers.set(id, server);
|
|
|
|
// Update consensus cluster
|
|
const members = Array.from(this.servers.keys());
|
|
if (members.length >= 3) {
|
|
this.raft = new WasmRaftNode(members[0], members);
|
|
}
|
|
|
|
return server;
|
|
}
|
|
|
|
async routeRequest(request) {
|
|
// Find best server for this request
|
|
const toolName = request.params?.name;
|
|
if (toolName) {
|
|
for (const [id, server] of this.servers) {
|
|
if (server.tools.has(toolName)) {
|
|
return { serverId: id, response: await server.handleRequest(request) };
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback to first server
|
|
const [firstId, firstServer] = this.servers.entries().next().value;
|
|
return { serverId: firstId, response: await firstServer.handleRequest(request) };
|
|
}
|
|
}`,
|
|
|
|
'self-healing': `// Self-Healing Swarm - Automatic recovery
|
|
class SelfHealingSwarm {
|
|
constructor() {
|
|
this.nodes = new Map();
|
|
this.heartbeatInterval = 5000;
|
|
this.failureThreshold = 15000;
|
|
}
|
|
|
|
addNode(id) {
|
|
this.nodes.set(id, {
|
|
identity: WasmIdentity.generate(),
|
|
lastHeartbeat: Date.now(),
|
|
status: 'healthy',
|
|
backup: null
|
|
});
|
|
}
|
|
|
|
heartbeat(nodeId) {
|
|
const node = this.nodes.get(nodeId);
|
|
if (node) {
|
|
node.lastHeartbeat = Date.now();
|
|
node.status = 'healthy';
|
|
}
|
|
}
|
|
|
|
checkHealth() {
|
|
const now = Date.now();
|
|
for (const [id, node] of this.nodes) {
|
|
if (now - node.lastHeartbeat > this.failureThreshold) {
|
|
console.log(\`Node \${id} failed! Initiating recovery...\`);
|
|
this.recover(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
recover(nodeId) {
|
|
const failed = this.nodes.get(nodeId);
|
|
failed.status = 'failed';
|
|
|
|
// Elect replacement
|
|
const healthy = Array.from(this.nodes.entries())
|
|
.filter(([_, n]) => n.status === 'healthy');
|
|
|
|
if (healthy.length > 0) {
|
|
const [replacementId, replacement] = healthy[0];
|
|
replacement.backup = nodeId;
|
|
console.log(\`Node \${replacementId} taking over for \${nodeId}\`);
|
|
}
|
|
}
|
|
}`,
|
|
|
|
emergent: `// Emergent Behavior - Agent evolution
|
|
class EmergentSwarm {`,
|
|
},
|
|
|
|
// Worker patterns
|
|
workers: {
|
|
none: `// Main Thread Execution
|
|
// All operations run on the main thread (simpler, but may block UI)
|
|
// Best for: Small datasets (<1000 vectors), simple operations`,
|
|
|
|
pool: `// Worker Pool - Auto-scaling background threads
|
|
import { WorkerPool } from '@ruvector/edge/worker-pool';
|
|
|
|
class SwarmWorkerPool {
|
|
constructor(options = {}) {
|
|
this.pool = null;
|
|
this.options = {
|
|
dimensions: options.dimensions || 128,
|
|
metric: options.metric || 'cosine',
|
|
useHnsw: options.useHnsw !== false,
|
|
poolSize: options.poolSize || navigator.hardwareConcurrency || 4
|
|
};
|
|
}
|
|
|
|
async init() {
|
|
// Create worker pool - auto-detects CPU cores
|
|
this.pool = new WorkerPool(
|
|
new URL('@ruvector/edge/worker', import.meta.url),
|
|
new URL('@ruvector/edge/ruvector_edge.js', import.meta.url),
|
|
this.options
|
|
);
|
|
await this.pool.init();
|
|
console.log(\`Worker pool ready: \${this.options.poolSize} workers\`);
|
|
}
|
|
|
|
// Non-blocking vector insert
|
|
async insert(vector, id, metadata) {
|
|
return this.pool.insert(vector, id, metadata);
|
|
}
|
|
|
|
// Parallel batch insert - splits across workers
|
|
async insertBatch(entries) {
|
|
return this.pool.insertBatch(entries);
|
|
}
|
|
|
|
// Background search - UI stays responsive
|
|
async search(query, k = 10) {
|
|
return this.pool.search(query, k);
|
|
}
|
|
|
|
// Parallel multi-query search
|
|
async searchBatch(queries, k = 10) {
|
|
return this.pool.searchBatch(queries, k);
|
|
}
|
|
|
|
// Get pool statistics
|
|
getStats() {
|
|
return this.pool.getStats();
|
|
}
|
|
|
|
// Clean up workers
|
|
terminate() {
|
|
this.pool.terminate();
|
|
}
|
|
}
|
|
|
|
// Usage example
|
|
const workerPool = new SwarmWorkerPool({ dimensions: 128 });
|
|
await workerPool.init();
|
|
|
|
// Insert 10,000 vectors in parallel (doesn't block UI)
|
|
const vectors = Array(10000).fill(null).map((_, i) => ({
|
|
vector: new Float32Array(128).fill(Math.random()),
|
|
id: \`doc-\${i}\`,
|
|
metadata: { index: i }
|
|
}));
|
|
await workerPool.insertBatch(vectors);
|
|
|
|
// Search runs in background
|
|
const results = await workerPool.search(queryVector, 10);`,
|
|
|
|
dedicated: `// Dedicated Worker - One worker per task type
|
|
class DedicatedWorkerManager {
|
|
constructor() {
|
|
this.workers = new Map();
|
|
}
|
|
|
|
// Create dedicated worker for a task type
|
|
createWorker(taskType, workerScript) {
|
|
const worker = new Worker(workerScript, { type: 'module' });
|
|
this.workers.set(taskType, {
|
|
worker,
|
|
busy: false,
|
|
pending: []
|
|
});
|
|
|
|
worker.onmessage = (e) => this.handleResponse(taskType, e.data);
|
|
return worker;
|
|
}
|
|
|
|
// Send task to dedicated worker
|
|
async execute(taskType, data) {
|
|
const workerInfo = this.workers.get(taskType);
|
|
if (!workerInfo) throw new Error(\`No worker for: \${taskType}\`);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
workerInfo.pending.push({ resolve, reject });
|
|
workerInfo.worker.postMessage(data);
|
|
});
|
|
}
|
|
|
|
handleResponse(taskType, data) {
|
|
const workerInfo = this.workers.get(taskType);
|
|
const pending = workerInfo.pending.shift();
|
|
if (data.error) pending.reject(new Error(data.error));
|
|
else pending.resolve(data.result);
|
|
}
|
|
|
|
terminateAll() {
|
|
for (const [_, info] of this.workers) {
|
|
info.worker.terminate();
|
|
}
|
|
this.workers.clear();
|
|
}
|
|
}
|
|
|
|
// Example: Separate workers for different operations
|
|
const manager = new DedicatedWorkerManager();
|
|
manager.createWorker('search', './search-worker.js');
|
|
manager.createWorker('embed', './embed-worker.js');
|
|
manager.createWorker('encrypt', './crypto-worker.js');`,
|
|
|
|
shared: `// Shared Worker - Cross-tab coordination
|
|
class SharedSwarmWorker {
|
|
constructor(workerUrl) {
|
|
this.worker = new SharedWorker(workerUrl, { type: 'module' });
|
|
this.port = this.worker.port;
|
|
this.requestId = 0;
|
|
this.pending = new Map();
|
|
|
|
this.port.onmessage = (e) => this.handleMessage(e.data);
|
|
this.port.start();
|
|
}
|
|
|
|
handleMessage(data) {
|
|
const pending = this.pending.get(data.requestId);
|
|
if (pending) {
|
|
this.pending.delete(data.requestId);
|
|
if (data.error) pending.reject(new Error(data.error));
|
|
else pending.resolve(data.result);
|
|
}
|
|
}
|
|
|
|
async execute(type, data) {
|
|
return new Promise((resolve, reject) => {
|
|
const requestId = this.requestId++;
|
|
this.pending.set(requestId, { resolve, reject });
|
|
this.port.postMessage({ type, requestId, data });
|
|
});
|
|
}
|
|
}
|
|
|
|
// Benefits of Shared Workers:
|
|
// 1. Single WASM instance shared across all tabs
|
|
// 2. Consistent vector index across browser tabs
|
|
// 3. Reduced memory usage (one index, not N copies)
|
|
// 4. Cross-tab agent coordination
|
|
|
|
// Example shared-worker.js:
|
|
/*
|
|
let vectorIndex = null;
|
|
const connections = [];
|
|
|
|
self.onconnect = (e) => {
|
|
const port = e.ports[0];
|
|
connections.push(port);
|
|
|
|
port.onmessage = async (event) => {
|
|
const { type, requestId, data } = event.data;
|
|
|
|
if (type === 'init' && !vectorIndex) {
|
|
const { init, WasmHnswIndex } = await import('./ruvector_edge.js');
|
|
await init();
|
|
vectorIndex = new WasmHnswIndex(128, 16, 200);
|
|
}
|
|
|
|
// All tabs share the same index
|
|
if (type === 'insert') {
|
|
vectorIndex.insert(data.id, new Float32Array(data.vector));
|
|
}
|
|
|
|
if (type === 'search') {
|
|
const results = vectorIndex.search(new Float32Array(data.query), data.k);
|
|
port.postMessage({ requestId, result: results });
|
|
}
|
|
};
|
|
|
|
port.start();
|
|
};
|
|
*/`
|
|
}
|
|
};
|
|
|
|
// Replace the last line of exotic.emergent to close the object properly
|
|
templates.exotic.emergent = `// Emergent Behavior - Agent evolution
|
|
class EmergentSwarm {
|
|
constructor(populationSize = 20) {
|
|
this.population = [];
|
|
this.generation = 0;
|
|
|
|
for (let i = 0; i < populationSize; i++) {
|
|
this.population.push({
|
|
identity: WasmIdentity.generate(),
|
|
genes: Array(10).fill(0).map(() => Math.random()),
|
|
fitness: 0
|
|
});
|
|
}
|
|
}
|
|
|
|
evolve(fitnessFunction, generations = 50) {
|
|
for (let g = 0; g < generations; g++) {
|
|
// Evaluate fitness
|
|
for (const agent of this.population) {
|
|
agent.fitness = fitnessFunction(agent.genes);
|
|
}
|
|
|
|
// Sort by fitness
|
|
this.population.sort((a, b) => b.fitness - a.fitness);
|
|
|
|
// Selection and reproduction
|
|
const elite = this.population.slice(0, 5);
|
|
const children = [];
|
|
|
|
while (children.length < this.population.length - elite.length) {
|
|
const parent1 = elite[Math.floor(Math.random() * elite.length)];
|
|
const parent2 = elite[Math.floor(Math.random() * elite.length)];
|
|
children.push(this.crossover(parent1, parent2));
|
|
}
|
|
|
|
this.population = [...elite, ...children];
|
|
this.generation++;
|
|
}
|
|
|
|
return this.population[0]; // Best agent
|
|
}
|
|
|
|
crossover(parent1, parent2) {
|
|
const child = {
|
|
identity: WasmIdentity.generate(),
|
|
genes: [],
|
|
fitness: 0
|
|
};
|
|
|
|
for (let i = 0; i < parent1.genes.length; i++) {
|
|
child.genes[i] = Math.random() > 0.5 ? parent1.genes[i] : parent2.genes[i];
|
|
// Mutation
|
|
if (Math.random() < 0.1) {
|
|
child.genes[i] += (Math.random() - 0.5) * 0.2;
|
|
}
|
|
}
|
|
|
|
return child;
|
|
}
|
|
}`
|
|
}
|
|
};
|
|
|
|
// Generate code
|
|
function generateCode() {
|
|
const hasMultipleModules = state.modules.length > 1 || !state.modules.includes('edge');
|
|
const packageName = hasMultipleModules ? '@ruvector/edge-full' : '@ruvector/edge';
|
|
|
|
let code = `// ${packageName} - Generated Swarm Configuration
|
|
// Topology: ${state.topology} | Transport: ${state.transport} | Use Case: ${state.usecase}
|
|
// Modules: ${state.modules.join(', ')} | Workers: ${state.workers} | Features: ${state.features.join(', ')}${state.exotic.length ? '\n// Exotic: ' + state.exotic.join(', ') : ''}
|
|
`;
|
|
|
|
// Generate imports based on selected modules
|
|
if (state.modules.includes('edge')) {
|
|
code += `
|
|
import init, {
|
|
WasmIdentity,
|
|
WasmCrypto,
|
|
${state.features.includes('hnsw') ? ' WasmHnswIndex,\n' : ''}${state.features.includes('semantic') ? ' WasmSemanticMatcher,\n' : ''}${state.features.includes('raft') ? ' WasmRaftNode,\n' : ''}${state.features.includes('pq') ? ' WasmHybridKeyPair,\n' : ''}${state.features.includes('spiking') ? ' WasmSpikingNetwork,\n' : ''}${state.features.includes('compression') ? ' WasmQuantizer,\n WasmAdaptiveCompressor,\n' : ''}} from '${packageName}${hasMultipleModules ? '/edge' : ''}';
|
|
`;
|
|
}
|
|
|
|
if (state.modules.includes('graph')) {
|
|
code += `
|
|
import graphInit, { WasmGraphStore } from '${packageName}/graph';
|
|
`;
|
|
}
|
|
|
|
if (state.modules.includes('rvlite')) {
|
|
code += `
|
|
import rvliteInit, { Database } from '${packageName}/rvlite';
|
|
`;
|
|
}
|
|
|
|
if (state.modules.includes('sona')) {
|
|
code += `
|
|
import sonaInit, { SonaEngine, ReasoningBank } from '${packageName}/sona';
|
|
`;
|
|
}
|
|
|
|
if (state.modules.includes('dag')) {
|
|
code += `
|
|
import dagInit, { Dag } from '${packageName}/dag';
|
|
`;
|
|
}
|
|
|
|
if (state.modules.includes('onnx')) {
|
|
code += `
|
|
import onnxInit, { WasmEmbedder } from '${packageName}/onnx';
|
|
`;
|
|
}
|
|
|
|
// Init calls
|
|
code += `
|
|
// Initialize WASM modules
|
|
await Promise.all([
|
|
${state.modules.includes('edge') ? ' init(),\n' : ''}${state.modules.includes('graph') ? ' graphInit(),\n' : ''}${state.modules.includes('rvlite') ? ' rvliteInit(),\n' : ''}${state.modules.includes('sona') ? ' sonaInit(),\n' : ''}${state.modules.includes('dag') ? ' dagInit(),\n' : ''}${state.modules.includes('onnx') ? ' onnxInit(),\n' : ''}]);
|
|
`;
|
|
|
|
// Add topology section
|
|
code += `
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// TOPOLOGY: ${state.topology.toUpperCase()}
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
${templates.topologies[state.topology]}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// TRANSPORT: ${state.transport.toUpperCase()}
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
${templates.transports[state.transport]}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// USE CASE: ${state.usecase.toUpperCase().replace('-', ' ')}
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
${templates.usecases[state.usecase]}`;
|
|
|
|
// Add worker pattern if not 'none'
|
|
if (state.workers !== 'none') {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// CONCURRENCY: ${state.workers.toUpperCase()} WORKERS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
${templates.workers[state.workers]}`;
|
|
}
|
|
|
|
// Add module-specific sections
|
|
if (state.modules.includes('graph')) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// GRAPH DATABASE (Neo4j-style)
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwarmGraph {
|
|
constructor() {
|
|
this.store = new WasmGraphStore();
|
|
}
|
|
|
|
// Create agent nodes
|
|
addAgent(id, type, capabilities) {
|
|
this.store.run_cypher(\`CREATE (a:Agent {id: '\${id}', type: '\${type}'})\`);
|
|
capabilities.forEach(cap => {
|
|
this.store.run_cypher(\`MATCH (a:Agent {id: '\${id}'}) CREATE (a)-[:HAS_CAPABILITY]->(:Capability {name: '\${cap}'})\`);
|
|
});
|
|
}
|
|
|
|
// Query connected agents
|
|
findConnectedAgents(agentId) {
|
|
return this.store.run_cypher(\`MATCH (a:Agent {id: '\${agentId}'})-[:CONNECTED_TO]->(b:Agent) RETURN b\`);
|
|
}
|
|
|
|
// Build agent relationship graph
|
|
connect(fromId, toId, relationship = 'CONNECTED_TO') {
|
|
this.store.run_cypher(\`MATCH (a:Agent {id: '\${fromId}'}), (b:Agent {id: '\${toId}'}) CREATE (a)-[:\${relationship}]->(b)\`);
|
|
}
|
|
}`;
|
|
}
|
|
|
|
if (state.modules.includes('rvlite')) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// VECTOR DATABASE (SQL/SPARQL/Cypher)
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwarmMemory {
|
|
constructor() {
|
|
this.db = new Database();
|
|
this.db.execute(\`
|
|
CREATE TABLE IF NOT EXISTS memories (
|
|
id TEXT PRIMARY KEY,
|
|
agent_id TEXT,
|
|
content TEXT,
|
|
embedding BLOB,
|
|
timestamp INTEGER
|
|
)
|
|
\`);
|
|
}
|
|
|
|
// Store memory with embedding
|
|
async store(agentId, content, embedding) {
|
|
const id = crypto.randomUUID();
|
|
this.db.execute(\`INSERT INTO memories VALUES (?, ?, ?, ?, ?)\`,
|
|
[id, agentId, content, embedding, Date.now()]);
|
|
return id;
|
|
}
|
|
|
|
// Semantic search across all agent memories
|
|
async search(queryEmbedding, limit = 10) {
|
|
return this.db.execute(\`
|
|
SELECT * FROM memories
|
|
ORDER BY vector_distance(embedding, ?)
|
|
LIMIT ?
|
|
\`, [queryEmbedding, limit]);
|
|
}
|
|
|
|
// SPARQL query for complex relationships
|
|
sparql(query) {
|
|
return this.db.sparql(query);
|
|
}
|
|
}`;
|
|
}
|
|
|
|
if (state.modules.includes('sona')) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// SELF-OPTIMIZING NEURAL ARCHITECTURE (SONA)
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwarmBrain {
|
|
constructor() {
|
|
this.engine = new SonaEngine();
|
|
this.reasoningBank = new ReasoningBank();
|
|
}
|
|
|
|
// Route task to best agent using neural routing
|
|
async route(task, availableAgents) {
|
|
const decision = await this.engine.route_request({
|
|
task,
|
|
agents: availableAgents.map(a => ({ id: a.id, capabilities: a.capabilities }))
|
|
});
|
|
|
|
// Learn from routing decisions
|
|
this.reasoningBank.record_trajectory({
|
|
state: task,
|
|
action: decision.selected_agent,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
return decision;
|
|
}
|
|
|
|
// Apply LoRA fine-tuning based on feedback
|
|
async adapt(feedback) {
|
|
await this.engine.apply_lora_update({
|
|
positive_examples: feedback.successes,
|
|
negative_examples: feedback.failures
|
|
});
|
|
}
|
|
|
|
// Get routing confidence
|
|
getConfidence(task) {
|
|
return this.engine.estimate_confidence(task);
|
|
}
|
|
}`;
|
|
}
|
|
|
|
if (state.modules.includes('dag')) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// WORKFLOW DAG (Task Orchestration)
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwarmWorkflow {
|
|
constructor() {
|
|
this.dag = new Dag();
|
|
this.tasks = new Map();
|
|
}
|
|
|
|
// Define workflow steps
|
|
addStep(id, executor, dependencies = []) {
|
|
this.dag.add_node(id);
|
|
this.tasks.set(id, { executor, status: 'pending' });
|
|
dependencies.forEach(dep => this.dag.add_edge(dep, id));
|
|
}
|
|
|
|
// Get execution order
|
|
getExecutionOrder() {
|
|
return this.dag.topological_sort();
|
|
}
|
|
|
|
// Execute workflow
|
|
async execute() {
|
|
const order = this.getExecutionOrder();
|
|
const results = new Map();
|
|
|
|
for (const stepId of order) {
|
|
const task = this.tasks.get(stepId);
|
|
task.status = 'running';
|
|
|
|
// Get results from dependencies
|
|
const deps = this.dag.get_dependencies(stepId);
|
|
const depResults = deps.map(d => results.get(d));
|
|
|
|
// Execute step
|
|
results.set(stepId, await task.executor(depResults));
|
|
task.status = 'complete';
|
|
}
|
|
|
|
return results;
|
|
}
|
|
}`;
|
|
}
|
|
|
|
if (state.modules.includes('onnx')) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ONNX EMBEDDINGS (HuggingFace Models)
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwarmEmbedder {
|
|
constructor() {
|
|
this.embedder = null;
|
|
}
|
|
|
|
async init(modelName = 'all-MiniLM-L6-v2') {
|
|
this.embedder = new WasmEmbedder();
|
|
await this.embedder.load_model(modelName);
|
|
console.log(\`Loaded embedding model: \${modelName}\`);
|
|
}
|
|
|
|
// Generate embedding for text
|
|
async embed(text) {
|
|
return await this.embedder.embed(text);
|
|
}
|
|
|
|
// Batch embed multiple texts (3.8x faster with parallel workers)
|
|
async embedBatch(texts) {
|
|
return await this.embedder.embed_batch(texts);
|
|
}
|
|
|
|
// Compute similarity between texts
|
|
async similarity(text1, text2) {
|
|
const [emb1, emb2] = await this.embedBatch([text1, text2]);
|
|
return this.cosineSimilarity(emb1, emb2);
|
|
}
|
|
|
|
cosineSimilarity(a, b) {
|
|
let dot = 0, normA = 0, normB = 0;
|
|
for (let i = 0; i < a.length; i++) {
|
|
dot += a[i] * b[i];
|
|
normA += a[i] * a[i];
|
|
normB += b[i] * b[i];
|
|
}
|
|
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
}
|
|
}`;
|
|
}
|
|
|
|
// Add exotic patterns
|
|
for (const exotic of state.exotic) {
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// EXOTIC: ${exotic.toUpperCase().replace('-', ' ')}
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
${templates.exotic[exotic]}`;
|
|
}
|
|
|
|
code += `
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// MAIN
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
async function main() {
|
|
console.log('🚀 Swarm initialized');
|
|
console.log(' Topology: ${state.topology}');
|
|
console.log(' Transport: ${state.transport}');
|
|
console.log(' Use Case: ${state.usecase}');
|
|
console.log(' Cost: $0/month');
|
|
|
|
// Initialize your swarm here...
|
|
}
|
|
|
|
main().catch(console.error);`;
|
|
|
|
return code;
|
|
}
|
|
|
|
// Highlight code
|
|
function highlight(code) {
|
|
return code
|
|
.replace(/(\/\/.*)/g, '<span class="comment">$1</span>')
|
|
.replace(/\b(import|from|export|const|let|var|function|class|async|await|return|if|else|for|while|new|this|extends|constructor|static|get|set)\b/g, '<span class="keyword">$1</span>')
|
|
.replace(/('.*?'|".*?"|`[^`]*`)/g, '<span class="string">$1</span>')
|
|
.replace(/\b(\d+\.?\d*)\b/g, '<span class="number">$1</span>')
|
|
.replace(/\b(WasmIdentity|WasmCrypto|WasmHnswIndex|WasmSemanticMatcher|WasmRaftNode|WasmHybridKeyPair|WasmSpikingNetwork|WasmQuantizer|WasmAdaptiveCompressor|Gun|RTCPeerConnection)\b/g, '<span class="const">$1</span>');
|
|
}
|
|
|
|
// Update display
|
|
function updateCode() {
|
|
const code = generateCode();
|
|
document.getElementById('generated-code').innerHTML = highlight(code);
|
|
}
|
|
|
|
// Event handlers
|
|
function setupHandlers() {
|
|
// Topology options
|
|
document.querySelectorAll('#topology-options .option').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
document.querySelectorAll('#topology-options .option').forEach(e => e.classList.remove('selected'));
|
|
el.classList.add('selected');
|
|
state.topology = el.dataset.value;
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Transport options
|
|
document.querySelectorAll('#transport-options .option').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
document.querySelectorAll('#transport-options .option').forEach(e => e.classList.remove('selected'));
|
|
el.classList.add('selected');
|
|
state.transport = el.dataset.value;
|
|
|
|
// Update latency estimate
|
|
const latencies = { gun: '~100ms', webrtc: '~50ms', libp2p: '~200ms', nostr: '~150ms' };
|
|
document.getElementById('msg-latency').textContent = latencies[state.transport];
|
|
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Use case options
|
|
document.querySelectorAll('#usecase-options .option').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
document.querySelectorAll('#usecase-options .option').forEach(e => e.classList.remove('selected'));
|
|
el.classList.add('selected');
|
|
state.usecase = el.dataset.value;
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Module options (multi-select)
|
|
document.querySelectorAll('#module-options .option').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
el.classList.toggle('selected');
|
|
const value = el.dataset.value;
|
|
if (el.classList.contains('selected')) {
|
|
if (!state.modules.includes(value)) {
|
|
state.modules.push(value);
|
|
}
|
|
} else {
|
|
state.modules = state.modules.filter(m => m !== value);
|
|
// Always keep at least edge
|
|
if (state.modules.length === 0) {
|
|
state.modules = ['edge'];
|
|
document.querySelector('#module-options .option[data-value="edge"]').classList.add('selected');
|
|
}
|
|
}
|
|
updateBundleSize();
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Worker options
|
|
document.querySelectorAll('#worker-options .option').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
document.querySelectorAll('#worker-options .option').forEach(e => e.classList.remove('selected'));
|
|
el.classList.add('selected');
|
|
state.workers = el.dataset.value;
|
|
|
|
// Update worker count display
|
|
const workerCounts = { none: '0', pool: '4', dedicated: '3', shared: '1' };
|
|
document.getElementById('worker-count').textContent = workerCounts[state.workers];
|
|
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Feature tags
|
|
document.querySelectorAll('#feature-tags .tag').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
el.classList.toggle('selected');
|
|
const value = el.dataset.value;
|
|
if (el.classList.contains('selected')) {
|
|
state.features.push(value);
|
|
} else {
|
|
state.features = state.features.filter(f => f !== value);
|
|
}
|
|
updateCode();
|
|
});
|
|
});
|
|
|
|
// Exotic tags
|
|
document.querySelectorAll('#exotic-tags .tag').forEach(el => {
|
|
el.addEventListener('click', () => {
|
|
el.classList.toggle('selected');
|
|
const value = el.dataset.value;
|
|
if (el.classList.contains('selected')) {
|
|
state.exotic.push(value);
|
|
} else {
|
|
state.exotic = state.exotic.filter(e => e !== value);
|
|
}
|
|
updateCode();
|
|
});
|
|
});
|
|
}
|
|
|
|
// Copy code
|
|
window.copyCode = function() {
|
|
const code = generateCode();
|
|
navigator.clipboard.writeText(code);
|
|
const btn = document.querySelector('.copy-btn');
|
|
btn.textContent = '✓ Copied!';
|
|
setTimeout(() => btn.textContent = '📋 Copy Code', 2000);
|
|
};
|
|
|
|
// Run demo
|
|
window.runDemo = async function() {
|
|
if (!wasmReady) {
|
|
document.getElementById('demo-output').textContent = 'WASM not loaded yet...';
|
|
return;
|
|
}
|
|
|
|
const output = document.getElementById('demo-output');
|
|
output.textContent = '🚀 Running live demo...\n\n';
|
|
|
|
try {
|
|
// Create identity
|
|
const identity = WasmIdentity.generate();
|
|
output.textContent += `✓ Identity created: ${identity.agent_id().slice(0, 16)}...\n`;
|
|
|
|
// Test crypto
|
|
const crypto = new WasmCrypto();
|
|
const key = crypto.generate_key();
|
|
const msg = new TextEncoder().encode('Hello Swarm!');
|
|
const encrypted = crypto.encrypt(key, msg);
|
|
const decrypted = crypto.decrypt(key, encrypted);
|
|
output.textContent += `✓ Encryption working: ${encrypted.length} bytes\n`;
|
|
|
|
// Test signing
|
|
const sig = identity.sign(msg);
|
|
const valid = identity.verify(msg, sig);
|
|
output.textContent += `✓ Signature valid: ${valid}\n`;
|
|
|
|
// Test features
|
|
if (state.features.includes('hnsw')) {
|
|
const index = new WasmHnswIndex(128, 16, 200);
|
|
index.insert('test', new Float32Array(128).fill(0.5));
|
|
output.textContent += `✓ HNSW index: ${index.len()} vectors\n`;
|
|
}
|
|
|
|
if (state.features.includes('semantic')) {
|
|
const matcher = new WasmSemanticMatcher();
|
|
matcher.register_agent('coder', 'programming code');
|
|
matcher.register_agent('writer', 'documentation writing');
|
|
const best = matcher.find_best_agent('write some code');
|
|
output.textContent += `✓ Semantic match: "${best}"\n`;
|
|
}
|
|
|
|
if (state.features.includes('raft')) {
|
|
const raft = new WasmRaftNode('node-1', ['node-1', 'node-2', 'node-3']);
|
|
raft.start_election();
|
|
output.textContent += `✓ Raft state: ${raft.state()}, term: ${raft.current_term()}\n`;
|
|
}
|
|
|
|
if (state.features.includes('pq')) {
|
|
const hybrid = WasmHybridKeyPair.generate();
|
|
const pqSig = hybrid.sign(msg);
|
|
output.textContent += `✓ Post-quantum sig: ${pqSig.length} bytes\n`;
|
|
}
|
|
|
|
if (state.features.includes('spiking')) {
|
|
const net = new WasmSpikingNetwork(4, 8, 2);
|
|
const spikes = net.forward([true, false, true, false]);
|
|
output.textContent += `✓ Spiking network: ${spikes.length} outputs\n`;
|
|
}
|
|
|
|
output.textContent += `\n🎉 Demo complete! Topology: ${state.topology}, Transport: ${state.transport}\n`;
|
|
output.textContent += `💰 Monthly cost: $0`;
|
|
|
|
} catch (err) {
|
|
output.textContent += `\n❌ Error: ${err.message}`;
|
|
}
|
|
};
|
|
|
|
// Initialize
|
|
setupHandlers();
|
|
updateCode();
|
|
</script>
|
|
</body>
|
|
</html>
|