@aleph-ai/tinyaleph 1.5.6 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,669 @@
1
+ /**
2
+ * Temporal Layer - Emergent Time
3
+ *
4
+ * Implements the emergent time mechanism from "A Design for a Sentient
5
+ * Observer" paper, Section 5.
6
+ *
7
+ * Key features:
8
+ * - Coherence-based moment detection (equations 18-20)
9
+ * - Entropy conditions for moment triggering
10
+ * - Subjective duration based on processed content
11
+ * - Phase transition rate monitoring
12
+ * - Temporal event logging
13
+ *
14
+ * @module observer/temporal
15
+ */
16
+
17
+ /**
18
+ * Moment - A discrete unit of experiential time
19
+ *
20
+ * Moments are triggered by coherence peaks or entropy conditions,
21
+ * not by external clock time.
22
+ */
23
+ class Moment {
24
+ /**
25
+ * Create a moment
26
+ * @param {Object} data - Moment data
27
+ */
28
+ constructor(data = {}) {
29
+ this.id = data.id || Moment.generateId();
30
+ this.timestamp = data.timestamp || Date.now();
31
+ this.clockTime = data.clockTime || Date.now();
32
+
33
+ // Trigger conditions
34
+ this.trigger = data.trigger || 'coherence'; // 'coherence' | 'entropy' | 'manual'
35
+ this.coherence = data.coherence || 0;
36
+ this.entropy = data.entropy || 0;
37
+ this.phaseTransitionRate = data.phaseTransitionRate || 0;
38
+
39
+ // Content
40
+ this.activePrimes = data.activePrimes || [];
41
+ this.smfSnapshot = data.smfSnapshot || null;
42
+ this.semanticContent = data.semanticContent || null;
43
+
44
+ // Subjective duration (equation 24)
45
+ // Δτ = β * Σ Ap log(Ap)
46
+ this.subjectiveDuration = data.subjectiveDuration || 0;
47
+
48
+ // Associations
49
+ this.previousMomentId = data.previousMomentId || null;
50
+ this.entangledMomentIds = data.entangledMomentIds || [];
51
+
52
+ // Metadata
53
+ this.notes = data.notes || '';
54
+ }
55
+
56
+ /**
57
+ * Generate a unique moment ID
58
+ */
59
+ static generateId() {
60
+ return `m_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
61
+ }
62
+
63
+ /**
64
+ * Serialize to JSON
65
+ */
66
+ toJSON() {
67
+ return {
68
+ id: this.id,
69
+ timestamp: this.timestamp,
70
+ clockTime: this.clockTime,
71
+ trigger: this.trigger,
72
+ coherence: this.coherence,
73
+ entropy: this.entropy,
74
+ phaseTransitionRate: this.phaseTransitionRate,
75
+ activePrimes: this.activePrimes,
76
+ smfSnapshot: this.smfSnapshot,
77
+ semanticContent: this.semanticContent,
78
+ subjectiveDuration: this.subjectiveDuration,
79
+ previousMomentId: this.previousMomentId,
80
+ entangledMomentIds: this.entangledMomentIds,
81
+ notes: this.notes
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Create from JSON
87
+ */
88
+ static fromJSON(data) {
89
+ return new Moment(data);
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Temporal Layer - Manages emergent time experience
95
+ *
96
+ * Time emerges from coherence events rather than external clock.
97
+ */
98
+ class TemporalLayer {
99
+ /**
100
+ * Create a temporal layer
101
+ * @param {Object} options - Configuration options
102
+ */
103
+ constructor(options = {}) {
104
+ // Thresholds (equation 18-20)
105
+ this.coherenceThreshold = options.coherenceThreshold || 0.7; // Cthresh
106
+ this.entropyMin = options.entropyMin || 0.05; // Hmin (lowered)
107
+ this.entropyMax = options.entropyMax || 0.95; // Hmax (raised)
108
+ this.phaseTransitionThreshold = options.phaseTransitionThreshold || 0.3;
109
+
110
+ // Duration scaling (equation 24)
111
+ this.beta = options.beta || 1.0; // β
112
+
113
+ // Debouncing for moment creation
114
+ this.minMomentInterval = options.minMomentInterval || 500; // Minimum ms between moments
115
+ this.lastMomentTime = 0;
116
+
117
+ // State
118
+ this.moments = [];
119
+ this.currentMoment = null;
120
+ this.subjectiveTime = 0; // Accumulated subjective duration
121
+ this.lastClockTime = Date.now();
122
+ this.momentCounter = 0;
123
+
124
+ // History tracking
125
+ this.coherenceHistory = [];
126
+ this.entropyHistory = [];
127
+ this.phaseHistory = [];
128
+ this.maxHistory = options.maxHistory || 1000;
129
+
130
+ // Callbacks
131
+ this.onMoment = options.onMoment || null;
132
+ }
133
+
134
+ /**
135
+ * Update temporal layer with current system state
136
+ * Returns true if a new moment was triggered
137
+ *
138
+ * @param {Object} state - Current system state
139
+ * @param {number} state.coherence - Global coherence (Cglobal)
140
+ * @param {number} state.entropy - System entropy (H)
141
+ * @param {Array<number>} state.phases - Current oscillator phases
142
+ * @param {Array<number>} state.activePrimes - Currently active primes
143
+ * @param {Object} state.smf - Current SMF state
144
+ * @param {Object} state.semanticContent - Current semantic content
145
+ */
146
+ update(state) {
147
+ const now = Date.now();
148
+ const dt = (now - this.lastClockTime) / 1000;
149
+ this.lastClockTime = now;
150
+
151
+ const { coherence, entropy, phases, activePrimes, smf, semanticContent } = state;
152
+
153
+ // Update history
154
+ this.coherenceHistory.push({ time: now, value: coherence });
155
+ this.entropyHistory.push({ time: now, value: entropy });
156
+
157
+ if (phases) {
158
+ this.phaseHistory.push({ time: now, phases: phases.slice() });
159
+ }
160
+
161
+ // Trim histories
162
+ this.trimHistories();
163
+
164
+ // Check moment trigger conditions (with debouncing)
165
+ const momentTriggered = this.checkMomentConditions(state);
166
+
167
+ if (momentTriggered.triggered) {
168
+ // Debounce: don't create moments too frequently
169
+ const now = Date.now();
170
+ if (now - this.lastMomentTime >= this.minMomentInterval) {
171
+ this.lastMomentTime = now;
172
+ return this.createMoment(momentTriggered.trigger, state);
173
+ }
174
+ }
175
+
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Check if moment conditions are met (equations 18-20)
181
+ * @param {Object} state - Current state
182
+ */
183
+ checkMomentConditions(state) {
184
+ const { coherence, entropy } = state;
185
+
186
+ // Condition 1: Coherence peak (equation 18)
187
+ // Cglobal(t) > Cthresh AND local maximum
188
+ const isCoherencePeak = this.isCoherencePeak(coherence);
189
+
190
+ // Condition 2: Entropy in valid range (equation 19)
191
+ // Hmin < H(t) < Hmax
192
+ const entropyValid = entropy > this.entropyMin && entropy < this.entropyMax;
193
+
194
+ // Condition 3: Phase transition (equation 20)
195
+ // Rate of phase change exceeds threshold
196
+ const phaseTransition = this.phaseTransitionRate() > this.phaseTransitionThreshold;
197
+
198
+ // Combined conditions
199
+ if (isCoherencePeak && entropyValid) {
200
+ return { triggered: true, trigger: 'coherence' };
201
+ }
202
+
203
+ if (phaseTransition && entropyValid) {
204
+ return { triggered: true, trigger: 'phase_transition' };
205
+ }
206
+
207
+ // Emergency moment if entropy at extremes (preventing freeze)
208
+ if (entropy < this.entropyMin * 0.5 || entropy > this.entropyMax * 1.5) {
209
+ return { triggered: true, trigger: 'entropy_extreme' };
210
+ }
211
+
212
+ return { triggered: false };
213
+ }
214
+
215
+ /**
216
+ * Check if current coherence is a local peak
217
+ * @param {number} coherence - Current coherence
218
+ */
219
+ isCoherencePeak(coherence) {
220
+ if (coherence < this.coherenceThreshold) return false;
221
+ if (this.coherenceHistory.length < 3) return false;
222
+
223
+ const recent = this.coherenceHistory.slice(-5);
224
+ if (recent.length < 3) return false;
225
+
226
+ // Check if current is higher than neighbors
227
+ const current = recent[recent.length - 1].value;
228
+ for (let i = 0; i < recent.length - 1; i++) {
229
+ if (recent[i].value >= current) return false;
230
+ }
231
+
232
+ return true;
233
+ }
234
+
235
+ /**
236
+ * Calculate rate of phase transitions
237
+ */
238
+ phaseTransitionRate() {
239
+ if (this.phaseHistory.length < 2) return 0;
240
+
241
+ const recent = this.phaseHistory.slice(-10);
242
+ if (recent.length < 2) return 0;
243
+
244
+ let totalChange = 0;
245
+ for (let i = 1; i < recent.length; i++) {
246
+ const prev = recent[i - 1].phases;
247
+ const curr = recent[i].phases;
248
+
249
+ if (!prev || !curr || prev.length !== curr.length) continue;
250
+
251
+ for (let j = 0; j < prev.length; j++) {
252
+ let delta = Math.abs(curr[j] - prev[j]);
253
+ // Handle phase wrapping
254
+ if (delta > Math.PI) delta = 2 * Math.PI - delta;
255
+ totalChange += delta;
256
+ }
257
+ }
258
+
259
+ const dt = (recent[recent.length - 1].time - recent[0].time) / 1000;
260
+ return dt > 0 ? totalChange / (recent.length * dt) : 0;
261
+ }
262
+
263
+ /**
264
+ * Create a new moment
265
+ * @param {string} trigger - Trigger type
266
+ * @param {Object} state - Current state
267
+ */
268
+ createMoment(trigger, state) {
269
+ const { coherence, entropy, activePrimes, smf, semanticContent } = state;
270
+
271
+ // Calculate subjective duration (equation 24)
272
+ // Δτ = β * Σ Ap log(Ap)
273
+ const subjectiveDuration = this.calculateSubjectiveDuration(state);
274
+
275
+ // Get SMF snapshot - check if smf has required methods
276
+ let smfSnapshot = null;
277
+ if (smf && smf.s && Array.isArray(smf.s)) {
278
+ smfSnapshot = {
279
+ components: smf.s.slice(),
280
+ entropy: typeof smf.smfEntropy === 'function' ? smf.smfEntropy() : 0
281
+ };
282
+ }
283
+
284
+ const moment = new Moment({
285
+ id: `m_${++this.momentCounter}`,
286
+ trigger,
287
+ coherence,
288
+ entropy,
289
+ phaseTransitionRate: this.phaseTransitionRate(),
290
+ activePrimes: activePrimes || [],
291
+ smfSnapshot,
292
+ semanticContent: semanticContent ? JSON.parse(JSON.stringify(semanticContent)) : null,
293
+ subjectiveDuration,
294
+ previousMomentId: this.currentMoment ? this.currentMoment.id : null
295
+ });
296
+
297
+ // Update subjective time
298
+ this.subjectiveTime += subjectiveDuration;
299
+
300
+ // Store moment
301
+ this.moments.push(moment);
302
+ this.currentMoment = moment;
303
+
304
+ // Callback
305
+ if (this.onMoment) {
306
+ this.onMoment(moment);
307
+ }
308
+
309
+ return moment;
310
+ }
311
+
312
+ /**
313
+ * Calculate subjective duration (equation 24)
314
+ * Δτ = β * Σ Ap log(Ap) (information content)
315
+ *
316
+ * @param {Object} state - Current state
317
+ */
318
+ calculateSubjectiveDuration(state) {
319
+ const { amplitudes } = state;
320
+
321
+ if (!amplitudes || amplitudes.length === 0) return this.beta;
322
+
323
+ // Sum of Ap * log(Ap) for non-zero amplitudes
324
+ let informationContent = 0;
325
+ for (const A of amplitudes) {
326
+ if (A > 1e-10) {
327
+ informationContent += A * Math.log(A + 1);
328
+ }
329
+ }
330
+
331
+ // Scale by beta, ensure positive
332
+ return Math.max(0.1, this.beta * Math.abs(informationContent) + 0.5);
333
+ }
334
+
335
+ /**
336
+ * Trim histories to max length
337
+ */
338
+ trimHistories() {
339
+ if (this.coherenceHistory.length > this.maxHistory) {
340
+ this.coherenceHistory = this.coherenceHistory.slice(-this.maxHistory);
341
+ }
342
+ if (this.entropyHistory.length > this.maxHistory) {
343
+ this.entropyHistory = this.entropyHistory.slice(-this.maxHistory);
344
+ }
345
+ if (this.phaseHistory.length > this.maxHistory) {
346
+ this.phaseHistory = this.phaseHistory.slice(-this.maxHistory);
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Force a moment (manual trigger)
352
+ * @param {Object} state - Current state
353
+ * @param {string} note - Optional note
354
+ */
355
+ forceMoment(state, note = '') {
356
+ const moment = this.createMoment('manual', state);
357
+ moment.notes = note;
358
+ return moment;
359
+ }
360
+
361
+ /**
362
+ * Get recent moments
363
+ * @param {number} count - Number of moments to return
364
+ */
365
+ recentMoments(count = 10) {
366
+ return this.moments.slice(-count);
367
+ }
368
+
369
+ /**
370
+ * Get moment by ID
371
+ * @param {string} id - Moment ID
372
+ */
373
+ getMoment(id) {
374
+ return this.moments.find(m => m.id === id);
375
+ }
376
+
377
+ /**
378
+ * Get moment chain (linked list of previous moments)
379
+ * @param {string} startId - Starting moment ID
380
+ * @param {number} maxDepth - Maximum chain depth
381
+ */
382
+ getMomentChain(startId, maxDepth = 10) {
383
+ const chain = [];
384
+ let current = this.getMoment(startId);
385
+
386
+ while (current && chain.length < maxDepth) {
387
+ chain.push(current);
388
+ if (current.previousMomentId) {
389
+ current = this.getMoment(current.previousMomentId);
390
+ } else {
391
+ break;
392
+ }
393
+ }
394
+
395
+ return chain;
396
+ }
397
+
398
+ /**
399
+ * Get subjective time elapsed
400
+ */
401
+ getSubjectiveTime() {
402
+ return this.subjectiveTime;
403
+ }
404
+
405
+ /**
406
+ * Get ratio of subjective to clock time
407
+ */
408
+ timeRatio() {
409
+ const clockElapsed = (Date.now() - this.moments[0]?.clockTime) / 1000;
410
+ if (clockElapsed < 1) return 1;
411
+ return this.subjectiveTime / clockElapsed;
412
+ }
413
+
414
+ /**
415
+ * Get average moment duration (clock time between moments)
416
+ */
417
+ averageMomentDuration() {
418
+ if (this.moments.length < 2) return 0;
419
+
420
+ let totalDuration = 0;
421
+ for (let i = 1; i < this.moments.length; i++) {
422
+ totalDuration += this.moments[i].clockTime - this.moments[i - 1].clockTime;
423
+ }
424
+
425
+ return totalDuration / (this.moments.length - 1);
426
+ }
427
+
428
+ /**
429
+ * Get temporal statistics
430
+ */
431
+ getStats() {
432
+ return {
433
+ momentCount: this.moments.length,
434
+ subjectiveTime: this.subjectiveTime,
435
+ averageMomentDuration: this.averageMomentDuration(),
436
+ timeRatio: this.timeRatio(),
437
+ lastCoherence: this.coherenceHistory.length > 0
438
+ ? this.coherenceHistory[this.coherenceHistory.length - 1].value : 0,
439
+ lastEntropy: this.entropyHistory.length > 0
440
+ ? this.entropyHistory[this.entropyHistory.length - 1].value : 0,
441
+ phaseTransitionRate: this.phaseTransitionRate()
442
+ };
443
+ }
444
+
445
+ /**
446
+ * Reset temporal layer
447
+ */
448
+ reset() {
449
+ this.moments = [];
450
+ this.currentMoment = null;
451
+ this.subjectiveTime = 0;
452
+ this.lastClockTime = Date.now();
453
+ this.momentCounter = 0;
454
+ this.coherenceHistory = [];
455
+ this.entropyHistory = [];
456
+ this.phaseHistory = [];
457
+ }
458
+
459
+ /**
460
+ * Serialize to JSON
461
+ */
462
+ toJSON() {
463
+ return {
464
+ moments: this.moments.map(m => m.toJSON()),
465
+ subjectiveTime: this.subjectiveTime,
466
+ momentCounter: this.momentCounter,
467
+ config: {
468
+ coherenceThreshold: this.coherenceThreshold,
469
+ entropyMin: this.entropyMin,
470
+ entropyMax: this.entropyMax,
471
+ phaseTransitionThreshold: this.phaseTransitionThreshold,
472
+ beta: this.beta
473
+ }
474
+ };
475
+ }
476
+
477
+ /**
478
+ * Load from JSON
479
+ * @param {Object} data - Serialized data
480
+ */
481
+ loadFromJSON(data) {
482
+ if (data.moments) {
483
+ this.moments = data.moments.map(m => Moment.fromJSON(m));
484
+ if (this.moments.length > 0) {
485
+ this.currentMoment = this.moments[this.moments.length - 1];
486
+ }
487
+ }
488
+ if (data.subjectiveTime) {
489
+ this.subjectiveTime = data.subjectiveTime;
490
+ }
491
+ if (data.momentCounter) {
492
+ this.momentCounter = data.momentCounter;
493
+ }
494
+ if (data.config) {
495
+ Object.assign(this, data.config);
496
+ }
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Temporal Pattern Detector
502
+ *
503
+ * Detects recurring patterns in temporal sequences,
504
+ * supporting anticipation and prediction.
505
+ */
506
+ class TemporalPatternDetector {
507
+ /**
508
+ * Create a pattern detector
509
+ * @param {Object} options - Configuration
510
+ */
511
+ constructor(options = {}) {
512
+ this.windowSize = options.windowSize || 5;
513
+ this.minPatternLength = options.minPatternLength || 2;
514
+ this.maxPatternLength = options.maxPatternLength || 10;
515
+ this.similarityThreshold = options.similarityThreshold || 0.8;
516
+
517
+ this.patterns = [];
518
+ }
519
+
520
+ /**
521
+ * Detect patterns in moment sequence
522
+ * @param {Array<Moment>} moments - Sequence of moments
523
+ */
524
+ detectPatterns(moments) {
525
+ if (moments.length < this.minPatternLength * 2) return [];
526
+
527
+ const signatures = moments.map(m => this.momentSignature(m));
528
+ const detected = [];
529
+
530
+ for (let len = this.minPatternLength; len <= Math.min(this.maxPatternLength, Math.floor(signatures.length / 2)); len++) {
531
+ for (let i = 0; i <= signatures.length - len * 2; i++) {
532
+ const pattern = signatures.slice(i, i + len);
533
+ const next = signatures.slice(i + len, i + len * 2);
534
+
535
+ if (this.matchPattern(pattern, next)) {
536
+ detected.push({
537
+ pattern: moments.slice(i, i + len),
538
+ repetition: moments.slice(i + len, i + len * 2),
539
+ startIndex: i,
540
+ length: len,
541
+ strength: this.patternStrength(pattern, next)
542
+ });
543
+ }
544
+ }
545
+ }
546
+
547
+ return this.deduplicatePatterns(detected);
548
+ }
549
+
550
+ /**
551
+ * Generate signature for a moment
552
+ * @param {Moment} moment - Moment to sign
553
+ */
554
+ momentSignature(moment) {
555
+ return {
556
+ trigger: moment.trigger,
557
+ coherenceLevel: Math.round(moment.coherence * 10) / 10,
558
+ entropyLevel: Math.round(moment.entropy * 10) / 10,
559
+ primeCount: moment.activePrimes.length,
560
+ dominantPrimes: moment.activePrimes.slice(0, 3)
561
+ };
562
+ }
563
+
564
+ /**
565
+ * Check if two signatures match
566
+ * @param {Array} pattern - First pattern
567
+ * @param {Array} other - Second pattern
568
+ */
569
+ matchPattern(pattern, other) {
570
+ if (pattern.length !== other.length) return false;
571
+
572
+ let matches = 0;
573
+ for (let i = 0; i < pattern.length; i++) {
574
+ if (this.signaturesMatch(pattern[i], other[i])) {
575
+ matches++;
576
+ }
577
+ }
578
+
579
+ return matches / pattern.length >= this.similarityThreshold;
580
+ }
581
+
582
+ /**
583
+ * Check if two moment signatures match
584
+ */
585
+ signaturesMatch(sig1, sig2) {
586
+ if (sig1.trigger !== sig2.trigger) return false;
587
+ if (Math.abs(sig1.coherenceLevel - sig2.coherenceLevel) > 0.2) return false;
588
+ if (Math.abs(sig1.entropyLevel - sig2.entropyLevel) > 0.2) return false;
589
+ return true;
590
+ }
591
+
592
+ /**
593
+ * Calculate pattern strength
594
+ */
595
+ patternStrength(pattern, repetition) {
596
+ let totalSimilarity = 0;
597
+ for (let i = 0; i < pattern.length; i++) {
598
+ const s1 = pattern[i];
599
+ const s2 = repetition[i];
600
+
601
+ let similarity = 0;
602
+ if (s1.trigger === s2.trigger) similarity += 0.3;
603
+ similarity += 0.3 * (1 - Math.abs(s1.coherenceLevel - s2.coherenceLevel));
604
+ similarity += 0.3 * (1 - Math.abs(s1.entropyLevel - s2.entropyLevel));
605
+ similarity += 0.1 * (s1.primeCount === s2.primeCount ? 1 : 0);
606
+
607
+ totalSimilarity += similarity;
608
+ }
609
+ return totalSimilarity / pattern.length;
610
+ }
611
+
612
+ /**
613
+ * Remove duplicate/overlapping patterns
614
+ */
615
+ deduplicatePatterns(patterns) {
616
+ const unique = [];
617
+
618
+ patterns.sort((a, b) => b.strength - a.strength);
619
+
620
+ for (const pattern of patterns) {
621
+ const overlaps = unique.some(u =>
622
+ Math.abs(u.startIndex - pattern.startIndex) < u.length
623
+ );
624
+
625
+ if (!overlaps) {
626
+ unique.push(pattern);
627
+ }
628
+ }
629
+
630
+ return unique;
631
+ }
632
+
633
+ /**
634
+ * Predict next moment characteristics based on patterns
635
+ * @param {Array<Moment>} moments - Recent moments
636
+ */
637
+ predictNext(moments) {
638
+ const patterns = this.detectPatterns(moments);
639
+
640
+ if (patterns.length === 0) return null;
641
+
642
+ const bestPattern = patterns[0];
643
+ const currentPosition = moments.length - bestPattern.startIndex;
644
+ const patternPosition = currentPosition % bestPattern.length;
645
+
646
+ if (patternPosition < bestPattern.pattern.length - 1) {
647
+ const nextInPattern = bestPattern.pattern[patternPosition + 1];
648
+ return {
649
+ predicted: this.momentSignature(nextInPattern),
650
+ confidence: bestPattern.strength,
651
+ patternLength: bestPattern.length
652
+ };
653
+ }
654
+
655
+ return null;
656
+ }
657
+ }
658
+
659
+ export {
660
+ Moment,
661
+ TemporalLayer,
662
+ TemporalPatternDetector
663
+ };
664
+
665
+ export default {
666
+ Moment,
667
+ TemporalLayer,
668
+ TemporalPatternDetector
669
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aleph-ai/tinyaleph",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "description": "Prime-resonant semantic computing framework - hypercomplex algebra, oscillator dynamics, and entropy-minimizing reasoning",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -90,6 +90,7 @@
90
90
  "physics/",
91
91
  "backends/",
92
92
  "engine/",
93
+ "observer/",
93
94
  "telemetry/",
94
95
  "types/",
95
96
  "docs/",