@timmeck/brain-core 2.9.1 → 2.11.0
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.
- package/consciousness-dashboard.html +1010 -0
- package/dist/consciousness/consciousness-server.d.ts +23 -0
- package/dist/consciousness/consciousness-server.js +145 -0
- package/dist/consciousness/consciousness-server.js.map +1 -0
- package/dist/consciousness/index.d.ts +4 -0
- package/dist/consciousness/index.js +3 -0
- package/dist/consciousness/index.js.map +1 -0
- package/dist/consciousness/thought-stream.d.ts +27 -0
- package/dist/consciousness/thought-stream.js +119 -0
- package/dist/consciousness/thought-stream.js.map +1 -0
- package/dist/consciousness/types.d.ts +33 -0
- package/dist/consciousness/types.js +3 -0
- package/dist/consciousness/types.js.map +1 -0
- package/dist/dream/dream-engine.d.ts +4 -0
- package/dist/dream/dream-engine.js +18 -0
- package/dist/dream/dream-engine.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/prediction/forecaster.d.ts +22 -0
- package/dist/prediction/forecaster.js +120 -0
- package/dist/prediction/forecaster.js.map +1 -0
- package/dist/prediction/index.d.ts +4 -0
- package/dist/prediction/index.js +4 -0
- package/dist/prediction/index.js.map +1 -0
- package/dist/prediction/prediction-engine.d.ts +59 -0
- package/dist/prediction/prediction-engine.js +301 -0
- package/dist/prediction/prediction-engine.js.map +1 -0
- package/dist/prediction/tracker.d.ts +27 -0
- package/dist/prediction/tracker.js +221 -0
- package/dist/prediction/tracker.js.map +1 -0
- package/dist/prediction/types.d.ts +85 -0
- package/dist/prediction/types.js +3 -0
- package/dist/prediction/types.js.map +1 -0
- package/dist/research/research-orchestrator.d.ts +8 -0
- package/dist/research/research-orchestrator.js +65 -1
- package/dist/research/research-orchestrator.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// ── Prediction Forecaster — Pure Math ────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Holt-Winters Double Exponential Smoothing + EWMA fallback.
|
|
4
|
+
// No DB dependency — pure functions, easy to test.
|
|
5
|
+
/**
|
|
6
|
+
* Holt-Winters Double Exponential Smoothing.
|
|
7
|
+
* Requires ≥ 5 data points. Returns forecast + trend + confidence.
|
|
8
|
+
*
|
|
9
|
+
* Level: l_t = α * y_t + (1-α) * (l_{t-1} + b_{t-1})
|
|
10
|
+
* Trend: b_t = β * (l_t - l_{t-1}) + (1-β) * b_{t-1}
|
|
11
|
+
* Forecast: ŷ_{t+h} = l_t + h * b_t
|
|
12
|
+
*/
|
|
13
|
+
export function holtWintersForecast(data, stepsAhead, alpha = 0.3, beta = 0.1) {
|
|
14
|
+
if (data.length < 2) {
|
|
15
|
+
return { value: data[0] ?? 0, trend: 0, confidence: 0.1, direction: 'stable', method: 'holt_winters', dataPoints: data.length };
|
|
16
|
+
}
|
|
17
|
+
// Initialize level and trend
|
|
18
|
+
let level = data[0];
|
|
19
|
+
let trend = data[1] - data[0];
|
|
20
|
+
const residuals = [];
|
|
21
|
+
for (let t = 1; t < data.length; t++) {
|
|
22
|
+
const y = data[t];
|
|
23
|
+
const prevLevel = level;
|
|
24
|
+
// Update level
|
|
25
|
+
level = alpha * y + (1 - alpha) * (prevLevel + trend);
|
|
26
|
+
// Update trend
|
|
27
|
+
trend = beta * (level - prevLevel) + (1 - beta) * trend;
|
|
28
|
+
// Track residuals for confidence calculation
|
|
29
|
+
const predicted = prevLevel + trend;
|
|
30
|
+
residuals.push(Math.abs(y - predicted));
|
|
31
|
+
}
|
|
32
|
+
// Forecast
|
|
33
|
+
const value = level + stepsAhead * trend;
|
|
34
|
+
// Confidence based on normalized MAE (1 - MAE/range)
|
|
35
|
+
const mae = residuals.length > 0
|
|
36
|
+
? residuals.reduce((a, b) => a + b, 0) / residuals.length
|
|
37
|
+
: 0;
|
|
38
|
+
const range = Math.max(...data) - Math.min(...data);
|
|
39
|
+
const normalizedMae = range > 0 ? mae / range : 0;
|
|
40
|
+
const confidence = Math.max(0.05, Math.min(0.95, 1 - normalizedMae));
|
|
41
|
+
// Direction
|
|
42
|
+
const trendRatio = range > 0 ? Math.abs(trend) / range : 0;
|
|
43
|
+
let direction;
|
|
44
|
+
if (trendRatio < 0.02) {
|
|
45
|
+
direction = 'stable';
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
direction = trend > 0 ? 'up' : 'down';
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
value,
|
|
52
|
+
trend,
|
|
53
|
+
confidence,
|
|
54
|
+
direction,
|
|
55
|
+
method: 'holt_winters',
|
|
56
|
+
dataPoints: data.length,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Exponentially Weighted Moving Average.
|
|
61
|
+
* Fallback for < 5 data points.
|
|
62
|
+
*/
|
|
63
|
+
export function ewmaForecast(data, alpha = 0.3) {
|
|
64
|
+
if (data.length === 0) {
|
|
65
|
+
return { value: 0, trend: 0, confidence: 0.1, direction: 'stable', method: 'ewma', dataPoints: 0 };
|
|
66
|
+
}
|
|
67
|
+
if (data.length === 1) {
|
|
68
|
+
return { value: data[0], trend: 0, confidence: 0.15, direction: 'stable', method: 'ewma', dataPoints: 1 };
|
|
69
|
+
}
|
|
70
|
+
let ewma = data[0];
|
|
71
|
+
for (let i = 1; i < data.length; i++) {
|
|
72
|
+
ewma = alpha * data[i] + (1 - alpha) * ewma;
|
|
73
|
+
}
|
|
74
|
+
// Simple trend from last two values
|
|
75
|
+
const last = data[data.length - 1];
|
|
76
|
+
const prev = data[data.length - 2];
|
|
77
|
+
const trend = last - prev;
|
|
78
|
+
// Low confidence for few data points
|
|
79
|
+
const confidence = Math.min(0.5, 0.15 + data.length * 0.08);
|
|
80
|
+
// Direction
|
|
81
|
+
const range = Math.max(...data) - Math.min(...data);
|
|
82
|
+
const trendRatio = range > 0 ? Math.abs(trend) / range : 0;
|
|
83
|
+
let direction;
|
|
84
|
+
if (trendRatio < 0.05) {
|
|
85
|
+
direction = 'stable';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
direction = trend > 0 ? 'up' : 'down';
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
value: ewma,
|
|
92
|
+
trend,
|
|
93
|
+
confidence,
|
|
94
|
+
direction,
|
|
95
|
+
method: 'ewma',
|
|
96
|
+
dataPoints: data.length,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Calibrate raw confidence using historical accuracy buckets.
|
|
101
|
+
* If the model was overconfident in a range, it adjusts downward — and vice versa.
|
|
102
|
+
*
|
|
103
|
+
* Returns value clamped to [0.01, 0.99].
|
|
104
|
+
*/
|
|
105
|
+
export function calibrateConfidence(rawConfidence, buckets) {
|
|
106
|
+
if (buckets.length === 0)
|
|
107
|
+
return Math.max(0.01, Math.min(0.99, rawConfidence));
|
|
108
|
+
// Find the matching bucket
|
|
109
|
+
const bucket = buckets.find(b => rawConfidence >= b.range_start && rawConfidence < b.range_end);
|
|
110
|
+
if (!bucket || bucket.predicted_count < 3) {
|
|
111
|
+
// Not enough data in this bucket — return raw
|
|
112
|
+
return Math.max(0.01, Math.min(0.99, rawConfidence));
|
|
113
|
+
}
|
|
114
|
+
// Adjust: if predicted 0.8 confidence but actual accuracy was 0.6, offset = -0.2
|
|
115
|
+
const midpoint = (bucket.range_start + bucket.range_end) / 2;
|
|
116
|
+
const offset = bucket.actual_accuracy - midpoint;
|
|
117
|
+
const adjusted = rawConfidence + offset;
|
|
118
|
+
return Math.max(0.01, Math.min(0.99, adjusted));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=forecaster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forecaster.js","sourceRoot":"","sources":["../../src/prediction/forecaster.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,6DAA6D;AAC7D,mDAAmD;AAInD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAc,EACd,UAAkB,EAClB,KAAK,GAAG,GAAG,EACX,IAAI,GAAG,GAAG;IAEV,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAClI,CAAC;IAED,6BAA6B;IAC7B,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IACrB,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IAEhC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,MAAM,SAAS,GAAG,KAAK,CAAC;QAExB,eAAe;QACf,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;QAEtD,eAAe;QACf,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;QAExD,6CAA6C;QAC7C,MAAM,SAAS,GAAG,SAAS,GAAG,KAAK,CAAC;QACpC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,WAAW;IACX,MAAM,KAAK,GAAG,KAAK,GAAG,UAAU,GAAG,KAAK,CAAC;IAEzC,qDAAqD;IACrD,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;QAC9B,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM;QACzD,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC;IAErE,YAAY;IACZ,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,SAAmC,CAAC;IACxC,IAAI,UAAU,GAAG,IAAI,EAAE,CAAC;QACtB,SAAS,GAAG,QAAQ,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,OAAO;QACL,KAAK;QACL,KAAK;QACL,UAAU;QACV,SAAS;QACT,MAAM,EAAE,cAAc;QACtB,UAAU,EAAE,IAAI,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,KAAK,GAAG,GAAG;IACtD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IACrG,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC7G,CAAC;IAED,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;IAC/C,CAAC;IAED,oCAAoC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;IAE1B,qCAAqC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE5D,YAAY;IACZ,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,SAAmC,CAAC;IACxC,IAAI,UAAU,GAAG,IAAI,EAAE,CAAC;QACtB,SAAS,GAAG,QAAQ,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI;QACX,KAAK;QACL,UAAU;QACV,SAAS;QACT,MAAM,EAAE,MAAM;QACd,UAAU,EAAE,IAAI,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,aAAqB,EAAE,OAA4B;IACrF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;IAE/E,2BAA2B;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,IAAI,CAAC,CAAC,WAAW,IAAI,aAAa,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAChG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAC1C,8CAA8C;QAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,iFAAiF;IACjF,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,GAAG,QAAQ,CAAC;IACjD,MAAM,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC;IAExC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { PredictionEngine, runPredictionMigration } from './prediction-engine.js';
|
|
2
|
+
export { PredictionTracker } from './tracker.js';
|
|
3
|
+
export { holtWintersForecast, ewmaForecast, calibrateConfidence } from './forecaster.js';
|
|
4
|
+
export type { PredictionDomain, PredictionStatus, PredictionEngineConfig, Prediction, PredictionAccuracy, PredictionSummary, ForecastResult, PredictionInput, MetricDataPoint, CalibrationBucket, } from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prediction/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { ThoughtStream } from '../consciousness/thought-stream.js';
|
|
3
|
+
import type { ResearchJournal } from '../research/journal.js';
|
|
4
|
+
import type { PredictionEngineConfig, Prediction, PredictionDomain, PredictionStatus, PredictionAccuracy, PredictionSummary, PredictionInput, ForecastResult, MetricDataPoint } from './types.js';
|
|
5
|
+
export declare function runPredictionMigration(db: Database.Database): void;
|
|
6
|
+
export declare class PredictionEngine {
|
|
7
|
+
private db;
|
|
8
|
+
private config;
|
|
9
|
+
private tracker;
|
|
10
|
+
private thoughtStream;
|
|
11
|
+
private journal;
|
|
12
|
+
private timer;
|
|
13
|
+
private calibrationOffset;
|
|
14
|
+
private log;
|
|
15
|
+
constructor(db: Database.Database, config: PredictionEngineConfig);
|
|
16
|
+
/** Set the ThoughtStream for consciousness integration. */
|
|
17
|
+
setThoughtStream(stream: ThoughtStream): void;
|
|
18
|
+
/** Set the Research Journal for logging notable predictions. */
|
|
19
|
+
setJournal(journal: ResearchJournal): void;
|
|
20
|
+
/** Start periodic resolution timer. */
|
|
21
|
+
start(): void;
|
|
22
|
+
/** Stop the resolution timer. */
|
|
23
|
+
stop(): void;
|
|
24
|
+
/** Record a metric data point. Called by domain event handlers. */
|
|
25
|
+
recordMetric(metric: string, value: number, domain?: PredictionDomain): void;
|
|
26
|
+
/**
|
|
27
|
+
* Generate a prediction for a specific metric.
|
|
28
|
+
* Returns null if insufficient data or confidence too low.
|
|
29
|
+
*/
|
|
30
|
+
predict(input: PredictionInput): Prediction | null;
|
|
31
|
+
/**
|
|
32
|
+
* Auto-predict for all tracked metrics that have enough data.
|
|
33
|
+
* Skips metrics with pending predictions. Respects maxPredictionsPerCycle.
|
|
34
|
+
*/
|
|
35
|
+
autoPredictAll(): Prediction[];
|
|
36
|
+
/**
|
|
37
|
+
* Resolve expired/due predictions against current metric values.
|
|
38
|
+
* Returns count of resolved predictions.
|
|
39
|
+
*/
|
|
40
|
+
resolveExpired(): number;
|
|
41
|
+
/** List predictions with optional filters. */
|
|
42
|
+
list(domain?: PredictionDomain, status?: PredictionStatus, limit?: number): Prediction[];
|
|
43
|
+
/** Get accuracy statistics. */
|
|
44
|
+
getAccuracy(domain?: PredictionDomain): PredictionAccuracy[];
|
|
45
|
+
/** Get full prediction summary. */
|
|
46
|
+
getSummary(): PredictionSummary;
|
|
47
|
+
/** Run a forecast on raw data. Uses Holt-Winters (≥ minDataPoints) or EWMA. */
|
|
48
|
+
forecast(data: number[], horizonMs: number): ForecastResult;
|
|
49
|
+
/** Get metric history as time series. */
|
|
50
|
+
getMetricHistory(metric: string, limit?: number): MetricDataPoint[];
|
|
51
|
+
/** Periodic cycle: resolve + auto-predict. */
|
|
52
|
+
private cycle;
|
|
53
|
+
/** Recalibrate confidence offset based on historical accuracy. */
|
|
54
|
+
private recalibrate;
|
|
55
|
+
/** Apply calibration to raw confidence. */
|
|
56
|
+
private applyCalibration;
|
|
57
|
+
/** Get all unique tracked metrics with their domains. */
|
|
58
|
+
private getTrackedMetrics;
|
|
59
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// ── Prediction Engine — Proactive Forecasting ────────────────
|
|
2
|
+
//
|
|
3
|
+
// Records domain metrics, generates Holt-Winters / EWMA predictions,
|
|
4
|
+
// resolves them against reality, and auto-calibrates confidence.
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { getLogger } from '../utils/logger.js';
|
|
7
|
+
import { holtWintersForecast, ewmaForecast, calibrateConfidence } from './forecaster.js';
|
|
8
|
+
import { PredictionTracker } from './tracker.js';
|
|
9
|
+
// ── Migration ───────────────────────────────────────────
|
|
10
|
+
export function runPredictionMigration(db) {
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS predictions (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14
|
+
prediction_id TEXT NOT NULL UNIQUE,
|
|
15
|
+
domain TEXT NOT NULL,
|
|
16
|
+
metric TEXT NOT NULL,
|
|
17
|
+
predicted_value REAL NOT NULL,
|
|
18
|
+
predicted_direction TEXT NOT NULL,
|
|
19
|
+
confidence REAL NOT NULL,
|
|
20
|
+
horizon_ms INTEGER NOT NULL,
|
|
21
|
+
reasoning TEXT NOT NULL DEFAULT '',
|
|
22
|
+
method TEXT NOT NULL,
|
|
23
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
24
|
+
actual_value REAL,
|
|
25
|
+
error REAL,
|
|
26
|
+
created_at INTEGER NOT NULL,
|
|
27
|
+
resolved_at INTEGER,
|
|
28
|
+
expires_at INTEGER NOT NULL,
|
|
29
|
+
evidence TEXT NOT NULL DEFAULT '{}'
|
|
30
|
+
);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_predictions_status ON predictions(status);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_predictions_domain ON predictions(domain);
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_predictions_metric ON predictions(metric);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_predictions_expires ON predictions(expires_at);
|
|
35
|
+
|
|
36
|
+
CREATE TABLE IF NOT EXISTS prediction_metrics (
|
|
37
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38
|
+
metric TEXT NOT NULL,
|
|
39
|
+
value REAL NOT NULL,
|
|
40
|
+
domain TEXT NOT NULL DEFAULT 'metric',
|
|
41
|
+
timestamp INTEGER NOT NULL
|
|
42
|
+
);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_pred_metrics_metric ON prediction_metrics(metric);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_pred_metrics_ts ON prediction_metrics(timestamp);
|
|
45
|
+
|
|
46
|
+
CREATE TABLE IF NOT EXISTS prediction_state (
|
|
47
|
+
id INTEGER PRIMARY KEY CHECK(id = 1),
|
|
48
|
+
total_predictions INTEGER NOT NULL DEFAULT 0,
|
|
49
|
+
total_resolved INTEGER NOT NULL DEFAULT 0,
|
|
50
|
+
total_correct INTEGER NOT NULL DEFAULT 0,
|
|
51
|
+
calibration_offset REAL NOT NULL DEFAULT 0.0,
|
|
52
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
53
|
+
);
|
|
54
|
+
INSERT OR IGNORE INTO prediction_state (id) VALUES (1);
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
// ── Engine ──────────────────────────────────────────────
|
|
58
|
+
export class PredictionEngine {
|
|
59
|
+
db;
|
|
60
|
+
config;
|
|
61
|
+
tracker;
|
|
62
|
+
thoughtStream = null;
|
|
63
|
+
journal = null;
|
|
64
|
+
timer = null;
|
|
65
|
+
calibrationOffset = 0;
|
|
66
|
+
log = getLogger();
|
|
67
|
+
constructor(db, config) {
|
|
68
|
+
this.db = db;
|
|
69
|
+
this.config = {
|
|
70
|
+
brainName: config.brainName,
|
|
71
|
+
defaultHorizonMs: config.defaultHorizonMs ?? 3_600_000,
|
|
72
|
+
expirationMs: config.expirationMs ?? 86_400_000,
|
|
73
|
+
ewmaAlpha: config.ewmaAlpha ?? 0.3,
|
|
74
|
+
trendBeta: config.trendBeta ?? 0.1,
|
|
75
|
+
minDataPoints: config.minDataPoints ?? 5,
|
|
76
|
+
minConfidence: config.minConfidence ?? 0.3,
|
|
77
|
+
maxPredictionsPerCycle: config.maxPredictionsPerCycle ?? 5,
|
|
78
|
+
resolveIntervalMs: config.resolveIntervalMs ?? 60_000,
|
|
79
|
+
};
|
|
80
|
+
runPredictionMigration(db);
|
|
81
|
+
this.tracker = new PredictionTracker(db);
|
|
82
|
+
// Load calibration offset from DB
|
|
83
|
+
this.calibrationOffset = this.tracker.getCalibrationOffset();
|
|
84
|
+
}
|
|
85
|
+
/** Set the ThoughtStream for consciousness integration. */
|
|
86
|
+
setThoughtStream(stream) {
|
|
87
|
+
this.thoughtStream = stream;
|
|
88
|
+
}
|
|
89
|
+
/** Set the Research Journal for logging notable predictions. */
|
|
90
|
+
setJournal(journal) {
|
|
91
|
+
this.journal = journal;
|
|
92
|
+
}
|
|
93
|
+
/** Start periodic resolution timer. */
|
|
94
|
+
start() {
|
|
95
|
+
if (this.timer)
|
|
96
|
+
return;
|
|
97
|
+
this.timer = setInterval(() => {
|
|
98
|
+
try {
|
|
99
|
+
this.cycle();
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
this.log.error(`[prediction] Cycle error: ${err.message}`);
|
|
103
|
+
}
|
|
104
|
+
}, this.config.resolveIntervalMs);
|
|
105
|
+
this.log.info(`[prediction] Engine started (resolve interval: ${this.config.resolveIntervalMs}ms)`);
|
|
106
|
+
}
|
|
107
|
+
/** Stop the resolution timer. */
|
|
108
|
+
stop() {
|
|
109
|
+
if (this.timer) {
|
|
110
|
+
clearInterval(this.timer);
|
|
111
|
+
this.timer = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Record a metric data point. Called by domain event handlers. */
|
|
115
|
+
recordMetric(metric, value, domain = 'metric') {
|
|
116
|
+
this.db.prepare(`
|
|
117
|
+
INSERT INTO prediction_metrics (metric, value, domain, timestamp) VALUES (?, ?, ?, ?)
|
|
118
|
+
`).run(metric, value, domain, Date.now());
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Generate a prediction for a specific metric.
|
|
122
|
+
* Returns null if insufficient data or confidence too low.
|
|
123
|
+
*/
|
|
124
|
+
predict(input) {
|
|
125
|
+
const horizonMs = input.horizon_ms ?? this.config.defaultHorizonMs;
|
|
126
|
+
const history = this.getMetricHistory(input.metric, 100);
|
|
127
|
+
if (history.length < 2)
|
|
128
|
+
return null;
|
|
129
|
+
const data = history.map(h => h.value);
|
|
130
|
+
const forecast = this.forecast(data, horizonMs);
|
|
131
|
+
// Apply calibration
|
|
132
|
+
const calibratedConfidence = this.applyCalibration(forecast.confidence);
|
|
133
|
+
if (calibratedConfidence < this.config.minConfidence)
|
|
134
|
+
return null;
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
const prediction = {
|
|
137
|
+
prediction_id: randomUUID(),
|
|
138
|
+
domain: input.domain,
|
|
139
|
+
metric: input.metric,
|
|
140
|
+
predicted_value: forecast.value,
|
|
141
|
+
predicted_direction: forecast.direction,
|
|
142
|
+
confidence: calibratedConfidence,
|
|
143
|
+
horizon_ms: horizonMs,
|
|
144
|
+
reasoning: input.reasoning ?? `${forecast.method} forecast (${forecast.dataPoints} points, trend: ${forecast.trend.toFixed(4)})`,
|
|
145
|
+
method: forecast.method,
|
|
146
|
+
status: 'pending',
|
|
147
|
+
created_at: now,
|
|
148
|
+
expires_at: now + this.config.expirationMs,
|
|
149
|
+
evidence: {
|
|
150
|
+
...input.evidence,
|
|
151
|
+
dataPoints: forecast.dataPoints,
|
|
152
|
+
trend: forecast.trend,
|
|
153
|
+
rawConfidence: forecast.confidence,
|
|
154
|
+
calibrationOffset: this.calibrationOffset,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
this.tracker.store(prediction);
|
|
158
|
+
// Update state
|
|
159
|
+
this.db.prepare(`
|
|
160
|
+
UPDATE prediction_state SET total_predictions = total_predictions + 1, updated_at = datetime('now') WHERE id = 1
|
|
161
|
+
`).run();
|
|
162
|
+
// Emit thought
|
|
163
|
+
this.thoughtStream?.emit('prediction', 'predicting', `Predicted ${input.metric}: ${forecast.direction} to ${forecast.value.toFixed(2)} (${(calibratedConfidence * 100).toFixed(0)}% confidence)`, calibratedConfidence > 0.7 ? 'notable' : 'routine');
|
|
164
|
+
// Journal high-confidence predictions
|
|
165
|
+
if (calibratedConfidence > 0.6 && this.journal) {
|
|
166
|
+
try {
|
|
167
|
+
this.journal.recordDiscovery(`Prediction: ${input.metric} → ${forecast.direction}`, `Forecasted ${input.metric} will go ${forecast.direction} to ${forecast.value.toFixed(2)} within ${(horizonMs / 60_000).toFixed(0)}min. Method: ${forecast.method}, confidence: ${(calibratedConfidence * 100).toFixed(0)}%.`, { prediction_id: prediction.prediction_id, ...prediction.evidence }, calibratedConfidence > 0.8 ? 'notable' : 'routine');
|
|
168
|
+
}
|
|
169
|
+
catch { /* best effort */ }
|
|
170
|
+
}
|
|
171
|
+
return prediction;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Auto-predict for all tracked metrics that have enough data.
|
|
175
|
+
* Skips metrics with pending predictions. Respects maxPredictionsPerCycle.
|
|
176
|
+
*/
|
|
177
|
+
autoPredictAll() {
|
|
178
|
+
const trackedMetrics = this.getTrackedMetrics();
|
|
179
|
+
const pendingMetrics = this.tracker.getMetricsWithPending();
|
|
180
|
+
const predictions = [];
|
|
181
|
+
for (const { metric, domain } of trackedMetrics) {
|
|
182
|
+
if (predictions.length >= this.config.maxPredictionsPerCycle)
|
|
183
|
+
break;
|
|
184
|
+
if (pendingMetrics.has(metric))
|
|
185
|
+
continue;
|
|
186
|
+
const prediction = this.predict({ domain, metric });
|
|
187
|
+
if (prediction)
|
|
188
|
+
predictions.push(prediction);
|
|
189
|
+
}
|
|
190
|
+
return predictions;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Resolve expired/due predictions against current metric values.
|
|
194
|
+
* Returns count of resolved predictions.
|
|
195
|
+
*/
|
|
196
|
+
resolveExpired() {
|
|
197
|
+
let resolved = 0;
|
|
198
|
+
// 1. Mark truly expired (past expiration, no data)
|
|
199
|
+
const expired = this.tracker.getPendingExpired();
|
|
200
|
+
for (const pred of expired) {
|
|
201
|
+
this.tracker.markExpired(pred.prediction_id);
|
|
202
|
+
resolved++;
|
|
203
|
+
}
|
|
204
|
+
// 2. Resolve predictions past their horizon
|
|
205
|
+
const resolvable = this.tracker.getPendingResolvable();
|
|
206
|
+
for (const pred of resolvable) {
|
|
207
|
+
// Get the latest metric value after the prediction was made
|
|
208
|
+
const row = this.db.prepare(`
|
|
209
|
+
SELECT AVG(value) as avg_value FROM prediction_metrics
|
|
210
|
+
WHERE metric = ? AND timestamp > ?
|
|
211
|
+
ORDER BY timestamp DESC LIMIT 10
|
|
212
|
+
`).get(pred.metric, pred.created_at);
|
|
213
|
+
if (row?.avg_value != null) {
|
|
214
|
+
this.tracker.resolve(pred.prediction_id, row.avg_value);
|
|
215
|
+
resolved++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// 3. Recalibrate if we resolved anything
|
|
219
|
+
if (resolved > 0) {
|
|
220
|
+
this.recalibrate();
|
|
221
|
+
}
|
|
222
|
+
return resolved;
|
|
223
|
+
}
|
|
224
|
+
/** List predictions with optional filters. */
|
|
225
|
+
list(domain, status, limit) {
|
|
226
|
+
return this.tracker.list(domain, status, limit);
|
|
227
|
+
}
|
|
228
|
+
/** Get accuracy statistics. */
|
|
229
|
+
getAccuracy(domain) {
|
|
230
|
+
return this.tracker.getAccuracy(domain);
|
|
231
|
+
}
|
|
232
|
+
/** Get full prediction summary. */
|
|
233
|
+
getSummary() {
|
|
234
|
+
const state = this.db.prepare('SELECT * FROM prediction_state WHERE id = 1').get();
|
|
235
|
+
const accuracy = this.tracker.getAccuracy();
|
|
236
|
+
const recent = this.tracker.list(undefined, undefined, 10);
|
|
237
|
+
const totalPredictions = state?.total_predictions ?? 0;
|
|
238
|
+
const pending = this.tracker.list(undefined, 'pending', 1000).length;
|
|
239
|
+
const resolved = totalPredictions - pending;
|
|
240
|
+
// Overall accuracy
|
|
241
|
+
const totalCorrect = accuracy.reduce((sum, a) => sum + a.correct, 0);
|
|
242
|
+
const totalResolved = accuracy.reduce((sum, a) => sum + a.total - a.expired, 0);
|
|
243
|
+
return {
|
|
244
|
+
total_predictions: totalPredictions,
|
|
245
|
+
pending,
|
|
246
|
+
resolved,
|
|
247
|
+
accuracy_rate: totalResolved > 0 ? totalCorrect / totalResolved : 0,
|
|
248
|
+
by_domain: accuracy,
|
|
249
|
+
calibration_offset: this.calibrationOffset,
|
|
250
|
+
recent,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/** Run a forecast on raw data. Uses Holt-Winters (≥ minDataPoints) or EWMA. */
|
|
254
|
+
forecast(data, horizonMs) {
|
|
255
|
+
// steps = horizon / avg interval between data points (default 1)
|
|
256
|
+
const steps = 1;
|
|
257
|
+
if (data.length >= this.config.minDataPoints) {
|
|
258
|
+
return holtWintersForecast(data, steps, this.config.ewmaAlpha, this.config.trendBeta);
|
|
259
|
+
}
|
|
260
|
+
return ewmaForecast(data, this.config.ewmaAlpha);
|
|
261
|
+
}
|
|
262
|
+
/** Get metric history as time series. */
|
|
263
|
+
getMetricHistory(metric, limit = 100) {
|
|
264
|
+
return this.db.prepare(`
|
|
265
|
+
SELECT value, timestamp FROM prediction_metrics
|
|
266
|
+
WHERE metric = ?
|
|
267
|
+
ORDER BY timestamp ASC
|
|
268
|
+
LIMIT ?
|
|
269
|
+
`).all(metric, limit);
|
|
270
|
+
}
|
|
271
|
+
// ── Private ─────────────────────────────────────────────
|
|
272
|
+
/** Periodic cycle: resolve + auto-predict. */
|
|
273
|
+
cycle() {
|
|
274
|
+
const resolved = this.resolveExpired();
|
|
275
|
+
if (resolved > 0) {
|
|
276
|
+
this.log.debug(`[prediction] Resolved ${resolved} predictions`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** Recalibrate confidence offset based on historical accuracy. */
|
|
280
|
+
recalibrate() {
|
|
281
|
+
this.calibrationOffset = this.tracker.getCalibrationOffset();
|
|
282
|
+
this.db.prepare(`
|
|
283
|
+
UPDATE prediction_state SET calibration_offset = ?, updated_at = datetime('now') WHERE id = 1
|
|
284
|
+
`).run(this.calibrationOffset);
|
|
285
|
+
}
|
|
286
|
+
/** Apply calibration to raw confidence. */
|
|
287
|
+
applyCalibration(rawConfidence) {
|
|
288
|
+
const buckets = this.tracker.getCalibrationBuckets();
|
|
289
|
+
return calibrateConfidence(rawConfidence, buckets);
|
|
290
|
+
}
|
|
291
|
+
/** Get all unique tracked metrics with their domains. */
|
|
292
|
+
getTrackedMetrics() {
|
|
293
|
+
return this.db.prepare(`
|
|
294
|
+
SELECT DISTINCT metric, domain FROM prediction_metrics
|
|
295
|
+
GROUP BY metric
|
|
296
|
+
HAVING COUNT(*) >= 2
|
|
297
|
+
ORDER BY COUNT(*) DESC
|
|
298
|
+
`).all();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=prediction-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prediction-engine.js","sourceRoot":"","sources":["../../src/prediction/prediction-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { Prediction, PredictionDomain, PredictionStatus, PredictionAccuracy, CalibrationBucket } from './types.js';
|
|
3
|
+
export declare class PredictionTracker {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(db: Database.Database);
|
|
6
|
+
/** Store a new prediction in the DB. */
|
|
7
|
+
store(prediction: Prediction): string;
|
|
8
|
+
/** Resolve a prediction against actual value. Returns the determined status. */
|
|
9
|
+
resolve(predictionId: string, actualValue: number): PredictionStatus;
|
|
10
|
+
/** List predictions with optional filters. */
|
|
11
|
+
list(domain?: PredictionDomain, status?: PredictionStatus, limit?: number): Prediction[];
|
|
12
|
+
/** Get accuracy statistics, optionally by domain. */
|
|
13
|
+
getAccuracy(domain?: PredictionDomain): PredictionAccuracy[];
|
|
14
|
+
/** Get calibration offset — average (confidence - actual_accuracy) across buckets. */
|
|
15
|
+
getCalibrationOffset(): number;
|
|
16
|
+
/** Get calibration buckets for confidence adjustment. */
|
|
17
|
+
getCalibrationBuckets(): CalibrationBucket[];
|
|
18
|
+
/** Get pending predictions that have expired (past expires_at). */
|
|
19
|
+
getPendingExpired(): Prediction[];
|
|
20
|
+
/** Get pending predictions that are within their horizon (ready for resolution check). */
|
|
21
|
+
getPendingResolvable(): Prediction[];
|
|
22
|
+
/** Mark a prediction as expired. */
|
|
23
|
+
markExpired(predictionId: string): void;
|
|
24
|
+
/** Get metrics with pending predictions (to skip in autoPredictAll). */
|
|
25
|
+
getMetricsWithPending(): Set<string>;
|
|
26
|
+
private rowToPrediction;
|
|
27
|
+
}
|