Skip to main content
Glama
signal.js6.79 kB
/** * Signal Protocol * * Unified abstraction for all inter-agent communication. * Combines neuralese crystallization, consensus weights, and phase coordination. * * A Signal is a typed message with confidence and source attribution. * Schema = proof obligation, Validation = proof discharge. */ const crypto = require('crypto'); /** * Model capability weights for consensus */ const ModelWeights = { 'anthropic/claude-sonnet-4': 1.0, 'anthropic/claude-opus-4': 1.0, 'openai/gpt-5-chat': 0.95, 'google/gemini-2.5-pro': 0.90, 'x-ai/grok-4': 0.85, 'deepseek/deepseek-chat-v3.1': 0.75, 'default': 0.5 }; /** * Crystallization patterns for understanding detection */ const CrystallizationPatterns = { ISOMORPHISM: /structural_isomorphism|documentation-as-code/i, PROGRESSIVE_DISCLOSURE: /tier_[0-2]|progressive|layered/i, EVENT_SOURCING: /replay|event_sourcing|temporal/i, PHASE_LOCK: /phase.?lock|resonan|attractor/i, CONTEXT_STORE: /context.?store|memory|persist/i, PERPLEXITY_DROP: /understand|clear|crystalliz|click/i, UNCERTAINTY: /unclear|confus|ambig|unsure/i }; /** * Signal types */ const SignalType = { QUERY: 'query', RESPONSE: 'response', CONSENSUS: 'consensus', CRYSTALLIZATION: 'crystallization', ERROR: 'error' }; /** * Core Signal class */ class Signal { constructor(type, payload, metadata = {}) { this.id = crypto.randomUUID(); this.type = type; this.payload = payload; this.confidence = metadata.confidence ?? 1.0; this.source = metadata.source ?? 'unknown'; this.timestamp = Date.now(); this.phase = metadata.phase ?? 0; this.tags = metadata.tags ?? []; } /** * Get model weight for consensus */ get weight() { return ModelWeights[this.source] ?? ModelWeights.default; } /** * Get crystallization score for understanding detection */ get crystallization() { return extractCrystallization(this.payload); } /** * Serialize for storage/transmission */ toJSON() { return { id: this.id, type: this.type, payload: this.payload, confidence: this.confidence, source: this.source, timestamp: this.timestamp, phase: this.phase, tags: this.tags }; } /** * Create from stored JSON */ static fromJSON(json) { const signal = new Signal(json.type, json.payload, { confidence: json.confidence, source: json.source, phase: json.phase, tags: json.tags }); signal.id = json.id; signal.timestamp = json.timestamp; return signal; } /** * Factory: Create query signal */ static query(payload, source, opts = {}) { return new Signal(SignalType.QUERY, payload, { source, ...opts }); } /** * Factory: Create response signal */ static response(payload, source, confidence = 1.0, opts = {}) { return new Signal(SignalType.RESPONSE, payload, { source, confidence, ...opts }); } /** * Factory: Create error signal */ static error(message, source, opts = {}) { return new Signal(SignalType.ERROR, { message }, { source, confidence: 0, ...opts }); } } /** * Extract crystallization score from text */ function extractCrystallization(payload) { const text = typeof payload === 'string' ? payload : JSON.stringify(payload); const patterns = {}; const positive = ['ISOMORPHISM', 'PROGRESSIVE_DISCLOSURE', 'EVENT_SOURCING', 'PHASE_LOCK', 'PERPLEXITY_DROP']; const negative = ['UNCERTAINTY']; let score = 0; for (const [name, regex] of Object.entries(CrystallizationPatterns)) { const matches = text.match(new RegExp(regex, 'gi')); const count = matches ? matches.length : 0; patterns[name] = { present: count > 0, count }; if (positive.includes(name)) score += count * 0.2; if (negative.includes(name)) score -= count * 0.1; } return { patterns, score: Math.max(0, Math.min(1, score)) }; } /** * SignalBus - Event-driven signal routing */ class SignalBus { constructor() { this.handlers = new Map(); this.history = []; this.maxHistory = 1000; } /** * Subscribe to signal type */ on(type, handler) { if (!this.handlers.has(type)) { this.handlers.set(type, []); } this.handlers.get(type).push(handler); return () => this.off(type, handler); } /** * Unsubscribe handler */ off(type, handler) { const handlers = this.handlers.get(type); if (handlers) { const idx = handlers.indexOf(handler); if (idx >= 0) handlers.splice(idx, 1); } } /** * Emit signal to handlers */ async emit(signal) { this.history.push(signal); if (this.history.length > this.maxHistory) { this.history.shift(); } const handlers = this.handlers.get(signal.type) ?? []; const wildcardHandlers = this.handlers.get('*') ?? []; const results = await Promise.allSettled( [...handlers, ...wildcardHandlers].map(h => h(signal)) ); return results.filter(r => r.status === 'fulfilled').map(r => r.value); } /** * Get signal history */ getHistory(filter = {}) { let result = [...this.history]; if (filter.type) result = result.filter(s => s.type === filter.type); if (filter.source) result = result.filter(s => s.source === filter.source); if (filter.since) result = result.filter(s => s.timestamp >= filter.since); return result; } } /** * Consensus calculator for multi-model agreement */ class ConsensusCalculator { constructor(opts = {}) { this.minAgreement = opts.minAgreement ?? 0.6; } /** * Calculate weighted consensus from signals */ calculate(signals) { if (!signals || signals.length === 0) { return { consensus: null, confidence: 0, method: 'no-signals' }; } if (signals.length === 1) { return { consensus: signals[0].payload, confidence: signals[0].confidence, method: 'single' }; } // Weight by model capability and individual confidence let totalWeight = 0; let weightedConfidence = 0; for (const signal of signals) { const weight = signal.weight * signal.confidence; totalWeight += weight; weightedConfidence += signal.confidence * weight; } // Use highest-weighted signal as consensus const sorted = [...signals].sort((a, b) => (b.weight * b.confidence) - (a.weight * a.confidence) ); return { consensus: sorted[0].payload, confidence: weightedConfidence / totalWeight, method: 'weighted', topSource: sorted[0].source, signalCount: signals.length }; } } module.exports = { Signal, SignalType, SignalBus, ConsensusCalculator, ModelWeights, CrystallizationPatterns, extractCrystallization };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wheattoast11/openrouter-deep-research-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server