@kernel.chat/kbot 3.83.0 → 3.85.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.
@@ -47,6 +47,14 @@ export declare function blackboardQuery(type?: BlackboardEntry['type']): Blackbo
47
47
  export declare function blackboardSubscribe(key: string, agentId: string, callback?: SubscriptionCallback): void;
48
48
  /** Get all decision-type entries (consensus view) */
49
49
  export declare function blackboardGetDecisions(): BlackboardEntry[];
50
+ type BlackboardTypeSubscriber = (entry: BlackboardEntry) => void;
51
+ /** Subscribe to blackboard entries by type. Use '*' for wildcard (all types). */
52
+ export declare function subscribeToBlackboard(type: string, callback: BlackboardTypeSubscriber): void;
53
+ /**
54
+ * Write an entry to the blackboard AND broadcast to all type-based subscribers.
55
+ * This is the preferred write path when cognitive modules should be notified.
56
+ */
57
+ export declare function broadcastToBlackboard(key: string, value: unknown, author: string, type: BlackboardEntry['type'], confidence?: number): BlackboardEntry;
50
58
  /** Clear the entire blackboard for a new task */
51
59
  export declare function blackboardClear(): void;
52
60
  export interface Proposal {
@@ -152,6 +152,31 @@ export function blackboardSubscribe(key, agentId, callback) {
152
152
  export function blackboardGetDecisions() {
153
153
  return blackboardQuery('decision');
154
154
  }
155
+ const typeSubscribers = new Map();
156
+ /** Subscribe to blackboard entries by type. Use '*' for wildcard (all types). */
157
+ export function subscribeToBlackboard(type, callback) {
158
+ if (!typeSubscribers.has(type))
159
+ typeSubscribers.set(type, []);
160
+ typeSubscribers.get(type).push(callback);
161
+ }
162
+ /**
163
+ * Write an entry to the blackboard AND broadcast to all type-based subscribers.
164
+ * This is the preferred write path when cognitive modules should be notified.
165
+ */
166
+ export function broadcastToBlackboard(key, value, author, type, confidence = 1.0) {
167
+ // Write to blackboard (this already notifies key-based subscribers)
168
+ const entry = blackboardWrite(key, value, author, type, confidence);
169
+ // Broadcast to type-based subscribers
170
+ const typeSubs = typeSubscribers.get(type) || [];
171
+ const wildcardSubs = typeSubscribers.get('*') || [];
172
+ for (const sub of [...typeSubs, ...wildcardSubs]) {
173
+ try {
174
+ sub(entry);
175
+ }
176
+ catch { /* subscriber errors don't break the bus */ }
177
+ }
178
+ return entry;
179
+ }
155
180
  /** Clear the entire blackboard for a new task */
156
181
  export function blackboardClear() {
157
182
  blackboard.entries.clear();
package/dist/agent.js CHANGED
@@ -41,10 +41,11 @@ import { CheckpointManager, newSessionId } from './checkpoint.js';
41
41
  import { TelemetryEmitter } from './telemetry.js';
42
42
  import { loadSkills } from './skills-loader.js';
43
43
  import { queueSignal, getCollectiveRecommendation, isCollectiveEnabled } from './collective.js';
44
+ import { subscribeToBlackboard } from './agent-protocol.js';
44
45
  import { ActiveInferenceEngine } from './free-energy.js';
45
46
  import { PredictiveEngine } from './predictive-processing.js';
46
47
  import { selectStrategy, recordStrategyOutcome } from './reasoning.js';
47
- import { getDriveState, updateMotivation } from './intentionality.js';
48
+ import { getDriveState, getMotivation, updateMotivation } from './intentionality.js';
48
49
  import { anticipateNext, recordUserAction, updateIdentity } from './temporal.js';
49
50
  import { estimateConfidence, updateSkillProfile, recordActualEffort } from './confidence.js';
50
51
  import { StrangeLoopDetector } from './strange-loops.js';
@@ -1022,12 +1023,56 @@ Always quote file paths that contain spaces. Never reference internal system nam
1022
1023
  const entropyScorer = new EntropyScorer();
1023
1024
  // ── Autopoiesis: self-maintaining system health ──
1024
1025
  const autopoietic = new AutopoieticSystem();
1025
- // ── Full cognitive stack (wired in v3.6.2) ──
1026
+ // ── Full cognitive stack (wired in v3.6.2, integrated in v3.85.0) ──
1026
1027
  const freeEnergy = new ActiveInferenceEngine();
1027
1028
  const predictive = new PredictiveEngine();
1028
1029
  const strangeLoops = new StrangeLoopDetector();
1029
1030
  const integrationMeter = new IntegrationMeter();
1031
+ // Blackboard journal for dream consolidation (Change 2: facts → dream journal)
1032
+ const blackboardDreamJournal = [];
1033
+ // Change 2: Subscribe cognitive modules to the blackboard broadcast bus
1034
+ try {
1035
+ // Everything → free energy engine as observations (global workspace)
1036
+ subscribeToBlackboard('*', (entry) => {
1037
+ freeEnergy.observeBlackboardEntry({
1038
+ type: entry.type,
1039
+ content: typeof entry.value === 'string' ? entry.value : String(entry.key),
1040
+ confidence: entry.confidence,
1041
+ });
1042
+ });
1043
+ // Facts → dream journal for later consolidation
1044
+ subscribeToBlackboard('fact', (entry) => {
1045
+ blackboardDreamJournal.push({
1046
+ content: typeof entry.value === 'string' ? entry.value : JSON.stringify(entry.value),
1047
+ timestamp: Date.now(),
1048
+ source: 'blackboard',
1049
+ });
1050
+ });
1051
+ // Decisions → intentionality drives (task completion signal)
1052
+ subscribeToBlackboard('decision', (entry) => {
1053
+ try {
1054
+ if (entry.confidence > 0.7) {
1055
+ updateMotivation({ type: 'task_success' });
1056
+ }
1057
+ }
1058
+ catch { /* non-critical */ }
1059
+ });
1060
+ // Hypotheses → predictive engine
1061
+ subscribeToBlackboard('hypothesis', (entry) => {
1062
+ // Feed hypotheses into the predictive engine's message history
1063
+ // so it can refine predictions based on intermediate reasoning
1064
+ try {
1065
+ const hypContent = typeof entry.value === 'string' ? entry.value : String(entry.key);
1066
+ predictive.evaluate(predictive.predict([hypContent], []), hypContent, []);
1067
+ }
1068
+ catch { /* non-critical */ }
1069
+ });
1070
+ }
1071
+ catch { /* blackboard subscriptions are non-critical */ }
1030
1072
  // Pre-execution intelligence: predict, plan, estimate (all non-critical)
1073
+ // Policy and tool bias are hoisted so they can be applied to the system prompt (Change 5)
1074
+ let cognitivePolicy = 'balanced';
1075
+ let cognitiveToolBias = { preferred: [], discouraged: [] };
1031
1076
  try {
1032
1077
  // Predictive processing — anticipate what the user will ask next
1033
1078
  const prediction = predictive.predict([originalMessage], toolSequenceLog);
@@ -1036,7 +1081,17 @@ Always quote file paths that contain spaces. Never reference internal system nam
1036
1081
  }
1037
1082
  // Free energy — observe the incoming message and update beliefs
1038
1083
  freeEnergy.observeMessage(originalMessage);
1039
- const policy = freeEnergy.recommendPolicy();
1084
+ // Change 1: Feed predictive engine results into free energy engine
1085
+ // The predictive engine's pattern classification improves the generative model.
1086
+ const pattern = prediction ? prediction.predictedAction : '';
1087
+ freeEnergy.integrateWithPredictiveEngine({
1088
+ pattern,
1089
+ confidence: prediction?.confidence ?? 0.3,
1090
+ accuracy: predictive.getState().accuracy,
1091
+ });
1092
+ // Change 5: Capture policy and tool bias for system prompt injection
1093
+ cognitivePolicy = freeEnergy.recommendPolicy();
1094
+ cognitiveToolBias = freeEnergy.recommendToolBias();
1040
1095
  // Confidence — how well can we handle this task?
1041
1096
  const conf = estimateConfidence(originalMessage, contextSnippet || '');
1042
1097
  // Reasoning — select the best strategy for this task type
@@ -1047,6 +1102,21 @@ Always quote file paths that contain spaces. Never reference internal system nam
1047
1102
  const anticipated = anticipateNext([originalMessage], originalMessage);
1048
1103
  }
1049
1104
  catch { /* cognitive stack is non-critical — never block the agent loop */ }
1105
+ // Change 5: Apply cognitive policy to system prompt
1106
+ // explore → broader thinking, exploit → direct proven approaches
1107
+ try {
1108
+ if (cognitivePolicy === 'explore') {
1109
+ systemContext += '\n\nNote: Consider unconventional approaches. The user may benefit from a different perspective than the obvious one.';
1110
+ }
1111
+ else if (cognitivePolicy === 'exploit') {
1112
+ systemContext += '\n\nNote: Use the most reliable, proven approach. The user needs a direct solution.';
1113
+ }
1114
+ // Apply tool bias from learned patterns
1115
+ if (cognitiveToolBias.preferred.length > 0) {
1116
+ systemContext += `\n\nPreferred tools based on learned patterns: ${cognitiveToolBias.preferred.join(', ')}`;
1117
+ }
1118
+ }
1119
+ catch { /* cognitive prompt injection is non-critical */ }
1050
1120
  // ── Tool execution pipeline ──
1051
1121
  const pipeline = options.pipeline ?? createDefaultPipeline({
1052
1122
  checkPermission,
@@ -1625,8 +1695,30 @@ Always quote file paths that contain spaces. Never reference internal system nam
1625
1695
  // ── Memory Scanner: stop and persist session stats ──
1626
1696
  stopMemoryScanner();
1627
1697
  // ── Dream Engine: consolidate session memories (non-blocking, $0 via Ollama) ──
1698
+ // Changes 3 & 4: Pass intentionality drives and surprise scores for
1699
+ // priority-guided consolidation and surprise-weighted replay selection.
1628
1700
  setBuddyMood('learning');
1629
- dreamAfterSession(sessionId);
1701
+ try {
1702
+ const motivation = getMotivation();
1703
+ const driveState = getDriveState();
1704
+ const dreamContext = {
1705
+ driveState: {
1706
+ curiosity: motivation.curiosity,
1707
+ frustration: driveState.frustrated ? 0.8 : 0.2,
1708
+ motivation: motivation.momentum,
1709
+ consolidation: driveState.overallSatisfaction < 0.5 ? 0.8 : 0.4,
1710
+ },
1711
+ surpriseScores: freeEnergy.getSurpriseHistory().map(s => ({
1712
+ message: s.message,
1713
+ surprise: s.surprise,
1714
+ })),
1715
+ };
1716
+ dreamAfterSession(sessionId, dreamContext);
1717
+ }
1718
+ catch {
1719
+ // Fallback: dream without cognitive context if anything fails
1720
+ dreamAfterSession(sessionId);
1721
+ }
1630
1722
  // ── Buddy Evolution: award XP for completing a session ──
1631
1723
  addBuddyXP(1);
1632
1724
  // ── Achievements: check for newly unlocked milestones ──
@@ -43,12 +43,23 @@ export declare function flushSignals(): Promise<void>;
43
43
  export declare function pullCollectiveHints(): Promise<RoutingHint[]>;
44
44
  /** Pull collective patterns (tool sequences, strategies) */
45
45
  export declare function pullCollectivePatterns(): Promise<CollectivePattern[]>;
46
- /** Get the best agent for a task category based on collective wisdom */
46
+ /**
47
+ * Apply temporal decay to collective patterns.
48
+ * Confidence halves every 30 days without reinforcement (exponential decay).
49
+ * Dead patterns below 0.05 confidence are pruned.
50
+ */
51
+ export declare function decayPatterns(patterns: CollectivePattern[]): CollectivePattern[];
52
+ /**
53
+ * Reinforce a pattern when a new instance confirms it.
54
+ * 15% confidence boost per confirmation, capped at 1.0.
55
+ */
56
+ export declare function reinforcePattern(pattern: CollectivePattern): CollectivePattern;
57
+ /** Get the best agent for a task category based on collective wisdom (with decay applied) */
47
58
  export declare function getCollectiveRecommendation(category: string): {
48
59
  agent: string;
49
60
  confidence: number;
50
61
  } | null;
51
- /** Get the best tool sequence for a task category based on collective wisdom */
62
+ /** Get the best tool sequence for a task category based on collective wisdom (with decay applied) */
52
63
  export declare function getCollectiveToolSequence(category: string): string[] | null;
53
64
  /** Get the current signal queue size (pending signals not yet flushed) */
54
65
  export declare function getSignalQueueSize(): number;
@@ -207,19 +207,64 @@ function loadCachedPatterns() {
207
207
  catch { /* corrupt cache */ }
208
208
  return [];
209
209
  }
210
+ // ── Temporal Decay + Positive Feedback (Change 6) ──
211
+ /**
212
+ * Apply temporal decay to collective patterns.
213
+ * Confidence halves every 30 days without reinforcement (exponential decay).
214
+ * Dead patterns below 0.05 confidence are pruned.
215
+ */
216
+ export function decayPatterns(patterns) {
217
+ const now = Date.now();
218
+ return patterns.map(p => {
219
+ const lastSeen = p.last_updated ? new Date(p.last_updated).getTime() : now;
220
+ const ageMs = now - lastSeen;
221
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
222
+ // Exponential decay: halve confidence every 30 days
223
+ // ln(2)/30 ≈ 0.023
224
+ const decayFactor = Math.exp(-0.023 * ageDays);
225
+ return {
226
+ ...p,
227
+ confidence: p.confidence * decayFactor,
228
+ // sample_count is preserved — it records historical evidence, not current relevance
229
+ };
230
+ }).filter(p => p.confidence > 0.05);
231
+ }
232
+ /**
233
+ * Reinforce a pattern when a new instance confirms it.
234
+ * 15% confidence boost per confirmation, capped at 1.0.
235
+ */
236
+ export function reinforcePattern(pattern) {
237
+ return {
238
+ ...pattern,
239
+ confidence: Math.min(1.0, pattern.confidence * 1.15),
240
+ sample_count: pattern.sample_count + 1,
241
+ last_updated: new Date().toISOString(),
242
+ };
243
+ }
210
244
  // ── Integration Helpers ──
211
- /** Get the best agent for a task category based on collective wisdom */
245
+ /** Get the best agent for a task category based on collective wisdom (with decay applied) */
212
246
  export function getCollectiveRecommendation(category) {
213
247
  const hints = loadCachedHints();
214
- const match = hints.find(h => h.category === category && h.confidence > 0.7 && h.sample_count > 50);
248
+ // Apply temporal decay to routing hints by mapping to CollectivePattern shape
249
+ const hintPatterns = hints.map(h => ({
250
+ type: 'routing_rule',
251
+ pattern: { category: h.category, best_agent: h.best_agent },
252
+ confidence: h.confidence,
253
+ sample_count: h.sample_count,
254
+ last_updated: new Date().toISOString(), // Cached hints don't track last_updated individually
255
+ }));
256
+ const decayed = decayPatterns(hintPatterns);
257
+ const match = decayed.find(p => p.pattern.category === category &&
258
+ p.confidence > 0.7 &&
259
+ p.sample_count > 50);
215
260
  if (match) {
216
- return { agent: match.best_agent, confidence: match.confidence };
261
+ return { agent: match.pattern.best_agent, confidence: match.confidence };
217
262
  }
218
263
  return null;
219
264
  }
220
- /** Get the best tool sequence for a task category based on collective wisdom */
265
+ /** Get the best tool sequence for a task category based on collective wisdom (with decay applied) */
221
266
  export function getCollectiveToolSequence(category) {
222
- const patterns = loadCachedPatterns();
267
+ const patterns = decayPatterns(loadCachedPatterns());
223
268
  const match = patterns.find(p => p.type === 'tool_sequence' &&
224
269
  p.pattern.category === category &&
225
270
  p.confidence > 0.7 &&
package/dist/dream.d.ts CHANGED
@@ -55,8 +55,23 @@ export interface ApplyResult {
55
55
  factsLearned: number;
56
56
  promptAmendments: number;
57
57
  }
58
+ /** Cognitive context passed from agent.ts to guide dream consolidation */
59
+ export interface DreamCognitiveContext {
60
+ /** Intentionality drive state */
61
+ driveState?: {
62
+ curiosity: number;
63
+ frustration: number;
64
+ motivation: number;
65
+ consolidation: number;
66
+ };
67
+ /** Per-message surprise scores from the free energy engine */
68
+ surpriseScores?: Array<{
69
+ message: string;
70
+ surprise: number;
71
+ }>;
72
+ }
58
73
  /** Run a full dream cycle — consolidate, reinforce, age */
59
- export declare function dream(sessionId?: string): Promise<DreamResult>;
74
+ export declare function dream(sessionId?: string, cognitiveContext?: DreamCognitiveContext): Promise<DreamResult>;
60
75
  export interface DreamResult {
61
76
  success: boolean;
62
77
  newInsights: number;
@@ -81,5 +96,5 @@ export declare function searchDreams(query: string): DreamInsight[];
81
96
  /** Manually reinforce a specific insight (user confirms it's still relevant) */
82
97
  export declare function reinforceInsight(insightId: string): boolean;
83
98
  /** Run dream after session ends (non-blocking) */
84
- export declare function dreamAfterSession(sessionId?: string): void;
99
+ export declare function dreamAfterSession(sessionId?: string, cognitiveContext?: DreamCognitiveContext): void;
85
100
  //# sourceMappingURL=dream.d.ts.map
package/dist/dream.js CHANGED
@@ -147,7 +147,7 @@ function archiveInsights(insights) {
147
147
  writeFileSync(archivePath, JSON.stringify(insights, null, 2));
148
148
  }
149
149
  // ── Consolidation Prompts ──
150
- function buildConsolidationPrompt(sessionHistory, existingInsights, existingMemory) {
150
+ function buildConsolidationPrompt(sessionHistory, existingInsights, existingMemory, driveState, surpriseScores) {
151
151
  const historyText = sessionHistory
152
152
  .map(t => `[${t.role}]: ${t.content.slice(0, 500)}`)
153
153
  .join('\n');
@@ -188,6 +188,36 @@ function buildConsolidationPrompt(sessionHistory, existingInsights, existingMemo
188
188
  }
189
189
  // ── Tier 7: User computer behavior — desktop observation ──
190
190
  const behaviorText = getBehaviorForDream(48) || '(no behavior data yet)';
191
+ // Change 4: Surprise-weighted replay selection.
192
+ // High-surprise messages are prioritized for consolidation (like biological sleep).
193
+ let replayHistoryText = historyText;
194
+ if (surpriseScores && surpriseScores.length > 0) {
195
+ const scored = sessionHistory.map(t => {
196
+ const msgSnippet = t.content.slice(0, 100);
197
+ const score = surpriseScores.find(s => msgSnippet.includes(s.message) || s.message.includes(msgSnippet.slice(0, 50)));
198
+ return { turn: t, surprise: score?.surprise ?? 0.5 };
199
+ });
200
+ // Sort by surprise (descending) and take top 60%
201
+ scored.sort((a, b) => b.surprise - a.surprise);
202
+ const topCount = Math.max(4, Math.ceil(scored.length * 0.6));
203
+ const replayTurns = scored.slice(0, topCount).map(s => s.turn);
204
+ replayHistoryText = replayTurns
205
+ .map(t => `[${t.role}]: ${t.content.slice(0, 500)}`)
206
+ .join('\n');
207
+ }
208
+ // Change 3: Drive-based consolidation priority guidance
209
+ let driveGuidance = '';
210
+ if (driveState) {
211
+ driveGuidance += '\n\nPRIORITY GUIDANCE (based on current intrinsic drives):';
212
+ if (driveState.curiosity > 0.7)
213
+ driveGuidance += '\n- HIGH CURIOSITY: Focus on novel connections and unexplored topics';
214
+ if (driveState.frustration > 0.5)
215
+ driveGuidance += '\n- FRUSTRATION DETECTED: Prioritize consolidating problem-solving patterns that resolved errors';
216
+ if (driveState.motivation > 0.8)
217
+ driveGuidance += '\n- HIGH MOTIVATION: Focus on patterns related to successful task completion';
218
+ if (driveState.consolidation > 0.6)
219
+ driveGuidance += '\n- CONSOLIDATION DRIVE: Focus on integrating fragmented knowledge into coherent structures';
220
+ }
191
221
  return `You are a memory consolidation system. Analyze this conversation session and ALL accumulated knowledge tiers to extract durable cross-tier insights.
192
222
 
193
223
  EXISTING DREAM INSIGHTS (Tier 4 — Dream Journal):
@@ -214,8 +244,9 @@ ${musicText}
214
244
  USER COMPUTER BEHAVIOR (Tier 7 — Desktop Observation):
215
245
  ${behaviorText}
216
246
 
217
- SESSION TO CONSOLIDATE:
218
- ${historyText}
247
+ SESSION TO CONSOLIDATE (surprise-weighted — high-value moments prioritized):
248
+ ${replayHistoryText}
249
+ ${driveGuidance}
219
250
 
220
251
  INSTRUCTIONS:
221
252
  Extract 1-5 insights by synthesizing across ALL tiers. Each insight should be:
@@ -468,9 +499,8 @@ function extractToolHintsFromInsight(text) {
468
499
  }
469
500
  return mapped;
470
501
  }
471
- // ── Core Dream Functions ──
472
502
  /** Run a full dream cycle — consolidate, reinforce, age */
473
- export async function dream(sessionId = 'default') {
503
+ export async function dream(sessionId = 'default', cognitiveContext) {
474
504
  const result = {
475
505
  success: false,
476
506
  newInsights: 0,
@@ -512,7 +542,8 @@ export async function dream(sessionId = 'default') {
512
542
  journal = aged;
513
543
  result.archived = archived.length;
514
544
  // Phase 2: Extract new insights from session (cross-tier consolidation)
515
- const consolidationPrompt = buildConsolidationPrompt(history, journal, memory);
545
+ // Changes 3 & 4: Pass drive state and surprise scores for priority guidance + replay weighting
546
+ const consolidationPrompt = buildConsolidationPrompt(history, journal, memory, cognitiveContext?.driveState, cognitiveContext?.surpriseScores);
516
547
  const rawInsights = await ollamaGenerate(consolidationPrompt);
517
548
  const newlyCreatedInsights = [];
518
549
  if (rawInsights) {
@@ -650,9 +681,9 @@ export function reinforceInsight(insightId) {
650
681
  return true;
651
682
  }
652
683
  /** Run dream after session ends (non-blocking) */
653
- export function dreamAfterSession(sessionId = 'default') {
684
+ export function dreamAfterSession(sessionId = 'default', cognitiveContext) {
654
685
  // Fire and forget — don't block the user
655
- dream(sessionId).catch(() => {
686
+ dream(sessionId, cognitiveContext).catch(() => {
656
687
  // Dream failed silently — non-critical
657
688
  });
658
689
  }
@@ -44,11 +44,42 @@ export declare class ActiveInferenceEngine {
44
44
  private toolOutcomeHistory;
45
45
  private beliefUpdates;
46
46
  private actionsTaken;
47
+ private recentObservations;
48
+ private surpriseLog;
47
49
  private readonly explorationThreshold;
48
50
  private readonly exploitationThreshold;
49
51
  private readonly learningRate;
50
52
  private readonly decayRate;
51
53
  constructor();
54
+ /**
55
+ * Integrate predictions from the PredictiveEngine to improve the generative model.
56
+ * If the predictive engine detected 'drill_down', the generative model should predict
57
+ * increasingly specific queries. If 'topic_switch', predict new domain.
58
+ */
59
+ integrateWithPredictiveEngine(predictions: {
60
+ pattern: string;
61
+ confidence: number;
62
+ accuracy: number;
63
+ }): void;
64
+ private mapPatternToIntent;
65
+ /**
66
+ * Observe a blackboard broadcast and update beliefs.
67
+ * Blackboard entries reduce entropy proportional to their confidence.
68
+ */
69
+ observeBlackboardEntry(entry: {
70
+ type: string;
71
+ content: string;
72
+ confidence: number;
73
+ }): void;
74
+ /**
75
+ * Get per-message surprise history for dream replay selection.
76
+ * High-surprise messages are worth consolidating during "sleep."
77
+ */
78
+ getSurpriseHistory(): Array<{
79
+ message: string;
80
+ surprise: number;
81
+ timestamp: number;
82
+ }>;
52
83
  /**
53
84
  * Observe a user message and compute surprise.
54
85
  * High surprise = our model of the user is wrong → update beliefs.
@@ -28,6 +28,8 @@ export class ActiveInferenceEngine {
28
28
  toolOutcomeHistory = [];
29
29
  beliefUpdates = 0;
30
30
  actionsTaken = 0;
31
+ recentObservations = [];
32
+ surpriseLog = [];
31
33
  // Hyperparameters
32
34
  explorationThreshold = 0.6; // Above this → explore
33
35
  exploitationThreshold = 0.3; // Below this → exploit
@@ -41,6 +43,49 @@ export class ActiveInferenceEngine {
41
43
  entropy: 1.0,
42
44
  };
43
45
  }
46
+ /**
47
+ * Integrate predictions from the PredictiveEngine to improve the generative model.
48
+ * If the predictive engine detected 'drill_down', the generative model should predict
49
+ * increasingly specific queries. If 'topic_switch', predict new domain.
50
+ */
51
+ integrateWithPredictiveEngine(predictions) {
52
+ if (predictions.confidence > 0.7) {
53
+ this.beliefs.predictedIntent = this.mapPatternToIntent(predictions.pattern);
54
+ this.beliefs.confidence = Math.max(this.beliefs.confidence, predictions.confidence * 0.8);
55
+ }
56
+ }
57
+ mapPatternToIntent(pattern) {
58
+ const mapping = {
59
+ 'iterative_refinement': 'refine_previous',
60
+ 'topic_switch': 'explore_new',
61
+ 'drill_down': 'deepen_understanding',
62
+ 'error_recovery': 'fix_problem',
63
+ 'capability_test': 'test_limits',
64
+ 'creative_request': 'create_something',
65
+ 'verification': 'verify_result',
66
+ 'follow_up': 'continue_thread',
67
+ 'meta_question': 'introspect',
68
+ };
69
+ return mapping[pattern] || 'general';
70
+ }
71
+ /**
72
+ * Observe a blackboard broadcast and update beliefs.
73
+ * Blackboard entries reduce entropy proportional to their confidence.
74
+ */
75
+ observeBlackboardEntry(entry) {
76
+ this.beliefs.entropy = Math.max(0, this.beliefs.entropy - entry.confidence * 0.1);
77
+ const snippet = typeof entry.content === 'string' ? entry.content.slice(0, 100) : '';
78
+ this.recentObservations.push(snippet);
79
+ if (this.recentObservations.length > 20)
80
+ this.recentObservations.shift();
81
+ }
82
+ /**
83
+ * Get per-message surprise history for dream replay selection.
84
+ * High-surprise messages are worth consolidating during "sleep."
85
+ */
86
+ getSurpriseHistory() {
87
+ return this.surpriseLog.slice(-50);
88
+ }
44
89
  /**
45
90
  * Observe a user message and compute surprise.
46
91
  * High surprise = our model of the user is wrong → update beliefs.
@@ -67,6 +112,14 @@ export class ActiveInferenceEngine {
67
112
  predictionError,
68
113
  };
69
114
  this.surpriseHistory.push(surprise);
115
+ // Track per-message surprise for dream replay selection (Change 4)
116
+ this.surpriseLog.push({
117
+ message: message.slice(0, 100),
118
+ surprise: predictionError,
119
+ timestamp: Date.now(),
120
+ });
121
+ if (this.surpriseLog.length > 100)
122
+ this.surpriseLog.shift();
70
123
  // Update beliefs via perceptual inference
71
124
  if (predictionError > this.explorationThreshold) {
72
125
  this.beliefs.confidence *= (1 - this.learningRate);
@@ -175,6 +228,8 @@ export class ActiveInferenceEngine {
175
228
  this.toolOutcomeHistory = [];
176
229
  this.beliefUpdates = 0;
177
230
  this.actionsTaken = 0;
231
+ this.recentObservations = [];
232
+ this.surpriseLog = [];
178
233
  }
179
234
  }
180
235
  //# sourceMappingURL=free-energy.js.map
@@ -81,6 +81,11 @@ export declare function tickParticles(particles: Particle[]): Particle[];
81
81
  * Render all particles to the canvas.
82
82
  */
83
83
  export declare function renderParticles(ctx: CanvasRenderingContext2D, particles: Particle[]): void;
84
+ /**
85
+ * Tick particles using Verlet integration (PBD style) instead of simple velocity.
86
+ * Adds floor constraints with realistic bounce and attractor constraints for orbital particles.
87
+ */
88
+ export declare function tickParticlesPBD(particles: Particle[], groundLevel?: number, attractorX?: number, attractorY?: number): Particle[];
84
89
  /**
85
90
  * Render a full procedural sky based on time of day, weather, and frame.
86
91
  */
@@ -155,4 +160,108 @@ export interface PostProcessOptions {
155
160
  * Apply screen-space post-processing effects.
156
161
  */
157
162
  export declare function renderPostProcessing(ctx: CanvasRenderingContext2D, width: number, height: number, frame: number, options: PostProcessOptions): void;
163
+ export interface RadianceGrid {
164
+ cells: Float32Array;
165
+ width: number;
166
+ height: number;
167
+ }
168
+ /**
169
+ * Create an empty radiance grid (20x12 cells covering the 1280x720 canvas).
170
+ */
171
+ export declare function createRadianceGrid(): RadianceGrid;
172
+ /**
173
+ * Update radiance grid by propagating light from all sources using inverse-square falloff.
174
+ * Clears grid each frame before re-propagating.
175
+ */
176
+ export declare function updateRadianceGrid(grid: RadianceGrid, lights: Light[]): void;
177
+ /**
178
+ * Render the radiance grid as an additive overlay.
179
+ * Each grid cell is drawn as a colored rect at low opacity, creating ambient light propagation.
180
+ */
181
+ export declare function renderRadianceOverlay(ctx: CanvasRenderingContext2D, grid: RadianceGrid, width: number, height: number): void;
182
+ /**
183
+ * Render subsurface scattering approximation on translucent robot panels.
184
+ * Creates a soft warm glow "leaking through" panel edges using shadowBlur + screen compositing.
185
+ */
186
+ export declare function renderSubsurfaceGlow(ctx: CanvasRenderingContext2D, panels: Array<{
187
+ x: number;
188
+ y: number;
189
+ width: number;
190
+ height: number;
191
+ color: string;
192
+ intensity: number;
193
+ }>): void;
194
+ /**
195
+ * Build SSS panel definitions for the kbot character.
196
+ */
197
+ export declare function buildSubsurfacePanels(robotX: number, robotY: number, scale: number, moodColor: string): Array<{
198
+ x: number;
199
+ y: number;
200
+ width: number;
201
+ height: number;
202
+ color: string;
203
+ intensity: number;
204
+ }>;
205
+ export interface FrameCache {
206
+ backgroundLayer: any | null;
207
+ bodyLayer: any | null;
208
+ lastBackgroundFrame: number;
209
+ lastBodyFrame: number;
210
+ }
211
+ /**
212
+ * Create an empty frame cache for importance-sampled rendering.
213
+ */
214
+ export declare function createFrameCache(): FrameCache;
215
+ /**
216
+ * Determine if a layer should be re-rendered this frame.
217
+ * - Background: every 4th frame (cached)
218
+ * - Body: every 2nd frame when idle (cached), always when moving
219
+ * - Effects: every frame
220
+ */
221
+ export declare function shouldRenderLayer(cache: FrameCache, layer: 'background' | 'body' | 'effects', currentFrame: number, isMoving?: boolean, moodChanged?: boolean, worldChanged?: boolean): boolean;
222
+ /**
223
+ * Cache a rendered layer as ImageData.
224
+ */
225
+ export declare function cacheLayer(cache: FrameCache, ctx: CanvasRenderingContext2D, layer: 'background' | 'body', x: number, y: number, w: number, h: number, currentFrame: number): void;
226
+ /**
227
+ * Draw a cached layer onto the canvas.
228
+ */
229
+ export declare function drawCachedLayer(ctx: CanvasRenderingContext2D, cache: FrameCache, layer: 'background' | 'body'): void;
230
+ /**
231
+ * Render volumetric fog with drifting horizontal bands.
232
+ * Fog is thinner near light sources and varies by biome.
233
+ */
234
+ export declare function renderVolumetricFog(ctx: CanvasRenderingContext2D, width: number, height: number, frame: number, fogDensity: number, fogColor: string, lightSources: Array<{
235
+ x: number;
236
+ y: number;
237
+ color: string;
238
+ intensity: number;
239
+ }>): void;
240
+ /**
241
+ * Get fog parameters for the current world state.
242
+ */
243
+ export declare function getFogParams(biome: string, timeOfDay: string): {
244
+ density: number;
245
+ color: string;
246
+ };
247
+ /**
248
+ * Cycle palette colors subtly based on frame, mood, and time of day.
249
+ * Creates a living, shimmering effect using HSL-based color shifting.
250
+ */
251
+ export declare function cyclePalette(basePalette: Record<string, string>, frame: number, mood: string, timeOfDay: string): Record<string, string>;
252
+ export interface AnimationParams {
253
+ blinkRate: number;
254
+ wobbleFreq: number;
255
+ wobbleAmp: number;
256
+ glowPulseSpeed: number;
257
+ breathSpeed: number;
258
+ energyLevel: number;
259
+ }
260
+ /**
261
+ * Compute animation parameters based on stream context.
262
+ * Higher engagement = faster, more energetic animations.
263
+ */
264
+ export declare function computeAnimationParams(chatRate: number, // messages per minute
265
+ viewerCount: number, // estimated viewers
266
+ mood: string, timeOfDay: string, streamDuration: number): AnimationParams;
158
267
  //# sourceMappingURL=render-engine.d.ts.map