@mindot/will 0.1.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.
Files changed (178) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +777 -0
  3. package/dist/index.d.ts +8144 -0
  4. package/dist/index.js +26231 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +73 -0
  7. package/src/cognition/agency/access.grants.ts +59 -0
  8. package/src/cognition/agency/competence.codec.ts +89 -0
  9. package/src/cognition/agency/engines/action.selector.ts +462 -0
  10. package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
  11. package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
  12. package/src/cognition/agency/engines/instruction.intake.ts +54 -0
  13. package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
  14. package/src/cognition/agency/engines/reafference.engine.ts +241 -0
  15. package/src/cognition/agency/execution.primitives.ts +118 -0
  16. package/src/cognition/agency/index.ts +58 -0
  17. package/src/cognition/agency/proactive.communicator.ts +274 -0
  18. package/src/cognition/agency/reconcile.learning.ts +82 -0
  19. package/src/cognition/agency/schemas/external.ts +59 -0
  20. package/src/cognition/agency/schemas/innate.ts +111 -0
  21. package/src/cognition/agency/schemas/repertoire.ts +246 -0
  22. package/src/cognition/agency/selection.scoring.ts +191 -0
  23. package/src/cognition/agency/types.ts +165 -0
  24. package/src/cognition/bus.ts +391 -0
  25. package/src/cognition/completion.inbox.ts +86 -0
  26. package/src/cognition/config.mirror.entities.ts +475 -0
  27. package/src/cognition/conversation.memory.ts +81 -0
  28. package/src/cognition/event.log.ts +116 -0
  29. package/src/cognition/event.schemas.ts +568 -0
  30. package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
  31. package/src/cognition/faculties/affective.blender.ts +562 -0
  32. package/src/cognition/faculties/attachment.evaluator.ts +432 -0
  33. package/src/cognition/faculties/attention.allocator.ts +422 -0
  34. package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
  35. package/src/cognition/faculties/bias.detector.ts +363 -0
  36. package/src/cognition/faculties/circadian.oscillator.ts +294 -0
  37. package/src/cognition/faculties/confidence.calibrator.ts +324 -0
  38. package/src/cognition/faculties/dream.simulator.ts +251 -0
  39. package/src/cognition/faculties/empathy.simulator.ts +253 -0
  40. package/src/cognition/faculties/energy.regulator.ts +320 -0
  41. package/src/cognition/faculties/episodic.consolidator.ts +728 -0
  42. package/src/cognition/faculties/executive.engine/commands.ts +459 -0
  43. package/src/cognition/faculties/executive.engine/config.ts +46 -0
  44. package/src/cognition/faculties/executive.engine/context.ts +605 -0
  45. package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
  46. package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
  47. package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
  48. package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
  49. package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
  50. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
  51. package/src/cognition/faculties/executive.engine/facet.ts +628 -0
  52. package/src/cognition/faculties/executive.engine/gating.ts +222 -0
  53. package/src/cognition/faculties/executive.engine/index.ts +6 -0
  54. package/src/cognition/faculties/executive.engine/messages.ts +102 -0
  55. package/src/cognition/faculties/executive.engine/parser.ts +380 -0
  56. package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
  57. package/src/cognition/faculties/executive.engine/types.ts +323 -0
  58. package/src/cognition/faculties/exteroception.ts +338 -0
  59. package/src/cognition/faculties/forgetting.curve.ts +202 -0
  60. package/src/cognition/faculties/frustration.evaluator.ts +280 -0
  61. package/src/cognition/faculties/goal.manager.ts +1008 -0
  62. package/src/cognition/faculties/inhibition.controller.ts +351 -0
  63. package/src/cognition/faculties/interoception.ts +417 -0
  64. package/src/cognition/faculties/introspection.engine.ts +246 -0
  65. package/src/cognition/faculties/known.entity.tracker.ts +439 -0
  66. package/src/cognition/faculties/loss.evaluator.ts +224 -0
  67. package/src/cognition/faculties/moral.evaluator.ts +437 -0
  68. package/src/cognition/faculties/novelty.detector.ts +254 -0
  69. package/src/cognition/faculties/persona.consolidator.ts +845 -0
  70. package/src/cognition/faculties/planning.engine/engine.ts +859 -0
  71. package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
  72. package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
  73. package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
  74. package/src/cognition/faculties/planning.engine/types.ts +143 -0
  75. package/src/cognition/faculties/reputation.tracker.ts +294 -0
  76. package/src/cognition/faculties/reward.evaluator.ts +304 -0
  77. package/src/cognition/faculties/self.model.updater.ts +677 -0
  78. package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
  79. package/src/cognition/faculties/semantic.engine/index.ts +6 -0
  80. package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
  81. package/src/cognition/faculties/semantic.engine/types.ts +53 -0
  82. package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
  83. package/src/cognition/faculties/social.perception.ts +333 -0
  84. package/src/cognition/faculties/spaced.repetition.ts +605 -0
  85. package/src/cognition/faculties/stress.regulator.ts +375 -0
  86. package/src/cognition/faculties/task.switcher.ts +239 -0
  87. package/src/cognition/faculties/theory.of.mind.ts +333 -0
  88. package/src/cognition/faculties/threat.evaluator.ts +312 -0
  89. package/src/cognition/faculties/working.memory.ts +406 -0
  90. package/src/cognition/generative.model.ts +344 -0
  91. package/src/cognition/heartbeat.ts +70 -0
  92. package/src/cognition/index.ts +291 -0
  93. package/src/cognition/instruction.handler.ts +146 -0
  94. package/src/cognition/memory/index.ts +35 -0
  95. package/src/cognition/memory/vector.adapter.ts +316 -0
  96. package/src/cognition/memory/vector.content.ts +47 -0
  97. package/src/cognition/memory/vector.embedder.ts +212 -0
  98. package/src/cognition/memory/vector.index.ts +459 -0
  99. package/src/cognition/memory/vector.types.ts +65 -0
  100. package/src/cognition/orchestrator.ts +142 -0
  101. package/src/cognition/persona.prior.ts +265 -0
  102. package/src/cognition/schema.registry.ts +145 -0
  103. package/src/cognition/senses/audition.engine/engine.ts +976 -0
  104. package/src/cognition/senses/audition.engine/salience.ts +59 -0
  105. package/src/cognition/senses/base.sense.engine.ts +117 -0
  106. package/src/cognition/senses/gustation.engine.ts +24 -0
  107. package/src/cognition/senses/index.ts +172 -0
  108. package/src/cognition/senses/olfaction.engine.ts +24 -0
  109. package/src/cognition/senses/somatosensation.engine.ts +23 -0
  110. package/src/cognition/senses/vision.engine.ts +23 -0
  111. package/src/cognition/types.ts +63 -0
  112. package/src/cognition/utilities/token.tracker.ts +492 -0
  113. package/src/core/abstracts.ts +60 -0
  114. package/src/core/async.engine.ts +539 -0
  115. package/src/core/clock.ts +196 -0
  116. package/src/core/completion.recorder.ts +122 -0
  117. package/src/core/conflict.detector.ts +140 -0
  118. package/src/core/distributed.ts +626 -0
  119. package/src/core/event.bus.ts +292 -0
  120. package/src/core/inbound.recorder.ts +100 -0
  121. package/src/core/index.ts +167 -0
  122. package/src/core/logger.ts +85 -0
  123. package/src/core/metrics.ts +107 -0
  124. package/src/core/orchestrator.ts +625 -0
  125. package/src/core/replay.ts +589 -0
  126. package/src/core/scenario.ts +120 -0
  127. package/src/core/serialization.ts +448 -0
  128. package/src/core/simulation.ts +197 -0
  129. package/src/core/snapshot.manager.ts +293 -0
  130. package/src/core/state.manager.ts +283 -0
  131. package/src/core/types.ts +274 -0
  132. package/src/core/utils.ts +82 -0
  133. package/src/core/wall.clock.ts +23 -0
  134. package/src/extensions/livestream.ext.ts +570 -0
  135. package/src/extensions/time.ext.ts +339 -0
  136. package/src/index.ts +91 -0
  137. package/src/llm/gate.ts +140 -0
  138. package/src/llm/index.ts +716 -0
  139. package/src/llm/summarizer.ts +170 -0
  140. package/src/llm/wire.contracts.ts +67 -0
  141. package/src/pma/eval.ts +651 -0
  142. package/src/pma/index.ts +1082 -0
  143. package/src/profiles/built-in.ts +7 -0
  144. package/src/profiles/companion.ts +28 -0
  145. package/src/profiles/company-brain.ts +54 -0
  146. package/src/profiles/customer-service.ts +30 -0
  147. package/src/profiles/game-npc.ts +20 -0
  148. package/src/profiles/index.ts +42 -0
  149. package/src/profiles/smart-home.ts +34 -0
  150. package/src/runners/coherence.runner.ts +49 -0
  151. package/src/runners/outreach.runner.ts +158 -0
  152. package/src/runners/social.runner.ts +182 -0
  153. package/src/runners/thin-shim.runner.ts +195 -0
  154. package/src/sdk/will.ts +334 -0
  155. package/src/stem/assembly.audit.ts +88 -0
  156. package/src/stem/distribution.ts +203 -0
  157. package/src/stem/guards/identity.coherence.ts +152 -0
  158. package/src/stem/guards/identity.guard.ts +227 -0
  159. package/src/stem/index.ts +1145 -0
  160. package/src/stem/mind.ts +1090 -0
  161. package/src/stem/tracts/ack.reconciler.ts +55 -0
  162. package/src/stem/tracts/biography.writer.ts +190 -0
  163. package/src/stem/tracts/effector.controller.ts +143 -0
  164. package/src/stem/tracts/health.reporter.ts +113 -0
  165. package/src/stem/tracts/inbound.queue.ts +54 -0
  166. package/src/stem/tracts/outbox.controller.ts +167 -0
  167. package/src/stem/tracts/outbox.writer.ts +133 -0
  168. package/src/stem/tracts/pma.controller.ts +109 -0
  169. package/src/stem/tracts/replay.controller.ts +177 -0
  170. package/src/stem/tracts/sensory.controller.ts +168 -0
  171. package/src/stem/tracts/session.logger.ts +157 -0
  172. package/src/stem/tracts/transport/index.ts +38 -0
  173. package/src/stem/tracts/transport/loopback.transport.ts +86 -0
  174. package/src/stem/tracts/transport/socketio.transport.ts +200 -0
  175. package/src/stem/tracts/transport/stream.transport.ts +152 -0
  176. package/src/stem/tracts/transport/types.ts +193 -0
  177. package/src/stem/tracts/transport.controller.ts +380 -0
  178. package/src/types.ts +116 -0
@@ -0,0 +1,417 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/interoception.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * Interoception — monitors internal bodily and mental state.
7
+ *
8
+ * Produces a unified "how I feel right now" percept by aggregating:
9
+ * - Energy level
10
+ * - Sleep pressure
11
+ * - Stress load
12
+ * - Circadian phase
13
+ * - Active emotions (from affective layer, once built)
14
+ * - Cognitive load
15
+ *
16
+ * This is the mind's sense of its own body — the foundation for
17
+ * subjective feeling states. Without interoception, emotions are
18
+ * just numbers; with it, they become felt experiences.
19
+ *
20
+ * Part of Shard 0 (Perceptual Layer) — runs every tick, synchronous.
21
+ */
22
+
23
+ import type {
24
+ Duration,
25
+ Tick,
26
+ SimulationContext,
27
+ ReadonlySimulationState,
28
+ StateCommands,
29
+ SimulationEvent,
30
+ } from '#core/types'
31
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
32
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
33
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
34
+ import { GenerativeModel } from '#cognition/generative.model'
35
+
36
+ export interface InteroceptionConfig {
37
+ /** Metric keys to include in the interoceptive percept */
38
+ monitoredMetrics?: string[]
39
+ /** Whether to emit a detailed interoceptive event each tick */
40
+ emitDetailEvent?: boolean
41
+ bus?: CognitiveBus
42
+ }
43
+
44
+ interface InteroceptiveSignal {
45
+ metric: string
46
+ value: number
47
+ interpretation: string
48
+ intensity: number // 0-1: how strongly this signal is felt
49
+ }
50
+
51
+ export class Interoception implements SimulationEngine, CognitiveEngine {
52
+ readonly name = 'interoception'
53
+
54
+ private _monitoredMetrics: string[]
55
+ private _emitDetailEvent: boolean
56
+
57
+ // Signal history for change detection
58
+ private _previousSignals = new Map<string, number>()
59
+
60
+ private _energyLevel: number = 100
61
+ private _sleepPressure: number = 0
62
+ private _stressLoad: number = 0
63
+
64
+ private _bus: CognitiveBus | null = null
65
+
66
+ private readonly _model = new GenerativeModel()
67
+
68
+
69
+ constructor( config: InteroceptionConfig = {} ){
70
+ this._bus = config.bus ?? null
71
+ this._monitoredMetrics = config.monitoredMetrics ?? [
72
+ 'energy.level',
73
+ 'sleep.pressure',
74
+ 'stress.load',
75
+ 'circadian.alertness',
76
+ 'circadian.mood_baseline',
77
+ 'attention.usage',
78
+ 'cognitive.load',
79
+ ]
80
+ this._emitDetailEvent = config.emitDetailEvent ?? false
81
+ }
82
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
83
+
84
+ // ── Engine interface ─────────────────────────────────────
85
+
86
+ subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","stress.state.changed","executive.prediction.formed"] }
87
+ publishes(): CognitiveEventSchema[] { return [] }
88
+
89
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
90
+ this._model.observe( e.type, e.salience )
91
+ switch( e.type ){
92
+ case 'energy.state.changed':
93
+ this._energyLevel = (e.payload as Record<string,number>)['level'] ?? this._energyLevel
94
+ break
95
+ case 'sleep.state.changed':
96
+ this._sleepPressure = (e.payload as Record<string,number>)['pressure'] ?? this._sleepPressure
97
+ break
98
+ case 'stress.state.changed':
99
+ this._stressLoad = (e.payload as Record<string,number>)['load'] ?? this._stressLoad
100
+ break
101
+ case 'executive.prediction.formed': {
102
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
103
+ if( p.predictedDomains.includes('interoception') )
104
+ this._model.setPrecision( 'interoception.intensity', 1.0 + p.confidence * 0.5 )
105
+ break
106
+ }
107
+ }
108
+ }
109
+
110
+ snapshot(): Record<string, unknown> {
111
+ return {
112
+ energyLevel: this._energyLevel,
113
+ sleepPressure: this._sleepPressure,
114
+ stressLoad: this._stressLoad,
115
+ }
116
+ }
117
+
118
+ async react(
119
+ _delta: Duration,
120
+ tick: Tick,
121
+ state: ReadonlySimulationState,
122
+ context: SimulationContext
123
+ ): Promise<EngineResult> {
124
+ const
125
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
126
+ commands: StateCommands = { set: [], metrics: [] }
127
+
128
+ const signals = this._readInternalState( state )
129
+
130
+ // Nothing to report yet — metrics haven't been seeded by regulatory engines
131
+ if( signals.length === 0 ) return { events: undefined, commands }
132
+
133
+ const significantChanges = this._detectChanges( signals )
134
+
135
+ // Build unified interoceptive percept
136
+ const
137
+ dominantSignal = signals.reduce( ( best, s ) => s.intensity > best.intensity ? s : best, signals[0]! ),
138
+ overallIntensity = signals.reduce( ( sum, s ) => sum + s.intensity, 0 ) / Math.max( signals.length, 1 ),
139
+ comfortLevel = this._computeComfort( signals )
140
+
141
+ // intero.mood: integrated mood signal (0-1).
142
+ // Blend of the direct circadian mood set-point and holistic homeostatic comfort.
143
+ // Comfort dominates (0.65) because energy/sleep/stress drive moment-to-moment
144
+ // mood more strongly than the slow-moving circadian baseline.
145
+ const moodBaseline = signals.find( s => s.metric === 'circadian.mood_baseline' )?.value ?? 0.5
146
+ const interoMood = moodBaseline * 0.35 + comfortLevel * 0.65
147
+
148
+ // Percept entity — the unified "how I feel" snapshot
149
+ commands.set!.push({
150
+ id: `interoception-${tick}`,
151
+ type: 'interoception',
152
+ metadata: {
153
+ tick,
154
+ dominantSignal: dominantSignal.metric,
155
+ dominantInterpretation: dominantSignal.interpretation,
156
+ overallIntensity,
157
+ comfort: comfortLevel,
158
+ signals: signals.map( s => ({
159
+ metric: s.metric,
160
+ value: s.value,
161
+ interpretation: s.interpretation,
162
+ intensity: s.intensity,
163
+ })),
164
+ },
165
+ })
166
+
167
+ // Clean up old interoception entities
168
+ commands.delete = this._collectStale( state, tick )
169
+
170
+ // Metrics
171
+ commands.metrics!.push(
172
+ [ 'interoception.comfort', comfortLevel ],
173
+ [ 'interoception.intensity', overallIntensity ],
174
+ [ 'intero.mood', interoMood ],
175
+ )
176
+
177
+ // Events for significant internal state changes
178
+ for( const change of significantChanges )
179
+ events.push({
180
+ type: 'interoception.change',
181
+ source: this.name,
182
+ payload: {
183
+ metric: change.metric,
184
+ previous: change.previous,
185
+ current: change.current,
186
+ interpretation: change.interpretation,
187
+ },
188
+ })
189
+
190
+ // Optional detailed event (for debugging/observability)
191
+ if( this._emitDetailEvent )
192
+ events.push({
193
+ type: 'interoception.detail',
194
+ source: this.name,
195
+ payload: { signals: signals.map( s => ({ ...s }) ) },
196
+ })
197
+
198
+
199
+ // Phase C: publish cognitive event
200
+ const _bus = this._bus
201
+ if( _bus )
202
+ _bus.publish({ type: 'interoception.state.updated', version: 1, sourceEngine: this.name, salience: Math.abs(comfortLevel - 0.5) * 0.8, payload: { comfort: comfortLevel, intensity: overallIntensity } })
203
+ // Phase D + F: rich state-change event — gated by prediction error
204
+ if( _bus ){
205
+ const predErr = this._model.observe( 'interoception.intensity', overallIntensity )
206
+ if( !predErr.gated )
207
+ _bus.publish({ type: 'interoception.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { comfort: comfortLevel, intensity: overallIntensity } })
208
+ }
209
+ return { events: events.length > 0 ? events : undefined, commands }
210
+ }
211
+
212
+ // ── Internal ─────────────────────────────────────────────
213
+
214
+ /**
215
+ * Read all monitored internal metrics and produce interpreted signals.
216
+ */
217
+ private _readInternalState( state: ReadonlySimulationState ): InteroceptiveSignal[] {
218
+ const signals: InteroceptiveSignal[] = []
219
+
220
+ for( const metric of this._monitoredMetrics ){
221
+ const value = state.metrics.get( metric )
222
+ if( value === undefined ) continue
223
+
224
+ const interpretation = this._interpret( metric, value )
225
+ const intensity = this._computeIntensity( metric, value )
226
+
227
+ signals.push({ metric, value, interpretation, intensity })
228
+ }
229
+
230
+ return signals
231
+ }
232
+
233
+ /**
234
+ * Interpret a metric value into a subjective description.
235
+ */
236
+ private _interpret( metric: string, value: number ): string {
237
+ switch( metric ){
238
+ case 'energy.level':
239
+ return value < 10 ? 'exhausted'
240
+ : value < 30 ? 'tired'
241
+ : value < 50 ? 'low energy'
242
+ : value < 70 ? 'energetic'
243
+ : 'fully energized'
244
+
245
+ case 'sleep.pressure':
246
+ return value < 10 ? 'well-rested'
247
+ : value < 30 ? 'slightly tired'
248
+ : value < 50 ? 'fatigued'
249
+ : value < 70 ? 'very tired'
250
+ : 'exhausted'
251
+
252
+ case 'stress.load':
253
+ return value < 20 ? 'calm'
254
+ : value < 40 ? 'slightly tense'
255
+ : value < 60 ? 'stressed'
256
+ : value < 80 ? 'very stressed'
257
+ : 'overwhelmed'
258
+
259
+ case 'circadian.alertness':
260
+ return value < 0.3 ? 'groggy'
261
+ : value < 0.5 ? 'drowsy'
262
+ : value < 0.7 ? 'alert'
263
+ : 'sharp'
264
+
265
+ case 'circadian.mood_baseline':
266
+ return value < 0.3 ? 'low mood'
267
+ : value < 0.5 ? 'neutral'
268
+ : value < 0.7 ? 'good mood'
269
+ : 'elevated mood'
270
+
271
+ case 'attention.usage':
272
+ return value < 0.3 ? 'unfocused'
273
+ : value < 0.6 ? 'moderately engaged'
274
+ : value < 0.9 ? 'focused'
275
+ : 'overloaded'
276
+
277
+ case 'cognitive.load':
278
+ return value < 0.3 ? 'idle'
279
+ : value < 0.6 ? 'thinking'
280
+ : value < 0.9 ? 'working hard'
281
+ : 'overloaded'
282
+
283
+ default:
284
+ return `${metric}: ${value.toFixed( 2 )}`
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Compute how intensely a signal is felt (deviation from comfort zone).
290
+ */
291
+ private _computeIntensity( metric: string, value: number ): number {
292
+ switch( metric ){
293
+ case 'energy.level':
294
+ // Low energy is intensely felt; high energy is barely noticed
295
+ return Math.max( 0, 1 - value / 100 )
296
+
297
+ case 'sleep.pressure':
298
+ // High pressure is intensely felt
299
+ return value / 100
300
+
301
+ case 'stress.load':
302
+ // Moderate stress is moderate; extreme is intense
303
+ return value < 30 ? value / 30 * 0.3
304
+ : value < 60 ? 0.3 + ( value - 30 ) / 30 * 0.4
305
+ : 0.7 + ( value - 60 ) / 40 * 0.3
306
+
307
+ case 'circadian.alertness':
308
+ // Low alertness is felt more than high alertness
309
+ return Math.max( 0, 0.7 - value )
310
+
311
+ case 'circadian.mood_baseline':
312
+ // Deviation from neutral in either direction
313
+ return Math.abs( value - 0.5 ) * 1.4
314
+
315
+ case 'attention.usage':
316
+ // Both underload and overload are felt
317
+ return value < 0.3 ? 0.5 - value
318
+ : value > 0.8 ? ( value - 0.8 ) * 2.5
319
+ : 0.1
320
+
321
+ case 'cognitive.load':
322
+ return value
323
+
324
+ default:
325
+ return Math.min( 1, Math.abs( value ) )
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Detect significant changes in internal signals since last tick.
331
+ */
332
+ private _detectChanges( signals: InteroceptiveSignal[] ): Array<{
333
+ metric: string
334
+ previous: number
335
+ current: number
336
+ interpretation: string
337
+ }> {
338
+ const changes: Array<{
339
+ metric: string
340
+ previous: number
341
+ current: number
342
+ interpretation: string
343
+ }> = []
344
+
345
+ for( const signal of signals ){
346
+ const previous = this._previousSignals.get( signal.metric )
347
+
348
+ if( previous !== undefined && Math.abs( signal.value - previous ) > 0.1 ){
349
+ changes.push({
350
+ metric: signal.metric,
351
+ previous,
352
+ current: signal.value,
353
+ interpretation: signal.interpretation,
354
+ })
355
+ }
356
+
357
+ this._previousSignals.set( signal.metric, signal.value )
358
+ }
359
+
360
+ return changes
361
+ }
362
+
363
+ /**
364
+ * Compute overall comfort from all signals.
365
+ * 1.0 = completely comfortable, 0.0 = deeply uncomfortable.
366
+ */
367
+ private _computeComfort( signals: InteroceptiveSignal[] ): number {
368
+ if( signals.length === 0 ) return 0.5
369
+
370
+ const weights: Record<string, number> = {
371
+ 'energy.level': 0.25,
372
+ 'sleep.pressure': 0.25,
373
+ 'stress.load': 0.30,
374
+ 'circadian.mood_baseline': 0.10,
375
+ 'attention.usage': 0.05,
376
+ 'cognitive.load': 0.05,
377
+ }
378
+
379
+ let weightedComfort = 0
380
+ let totalWeight = 0
381
+
382
+ for( const signal of signals ){
383
+ const weight = weights[ signal.metric ] ?? 0.05
384
+ totalWeight += weight
385
+
386
+ // Map each metric to a comfort contribution (0-1)
387
+ const comfort = this._metricToComfort( signal.metric, signal.value )
388
+ weightedComfort += comfort * weight
389
+ }
390
+
391
+ return totalWeight > 0 ? weightedComfort / totalWeight : 0.5
392
+ }
393
+
394
+ private _metricToComfort( metric: string, value: number ): number {
395
+ switch( metric ){
396
+ case 'energy.level': return value / 100
397
+ case 'sleep.pressure': return 1 - value / 100
398
+ case 'stress.load': return 1 - value / 100
399
+ case 'circadian.alertness': return value
400
+ case 'circadian.mood_baseline': return value
401
+ case 'attention.usage': return value > 0.8 ? 0.3 : value < 0.2 ? 0.4 : 0.8
402
+ case 'cognitive.load': return 1 - value
403
+ default: return 0.5
404
+ }
405
+ }
406
+
407
+ private _collectStale( state: ReadonlySimulationState, currentTick: Tick ): string[] {
408
+ const stale: string[] = []
409
+ for( const [ id, entity ] of state.entities ){
410
+ if( entity.type === 'interoception' && typeof entity.metadata?.tick === 'number'){
411
+ if( currentTick - entity.metadata.tick > 2 )
412
+ stale.push( id )
413
+ }
414
+ }
415
+ return stale
416
+ }
417
+ }
@@ -0,0 +1,246 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/introspection.engine.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * IntrospectionEngine — satellite mode.
7
+ *
8
+ * Reads the most recent ExecutiveEngine output for introspections.
9
+ * Performs heuristic self-analysis between executive runs for minor events.
10
+ * No longer makes its own LLM calls.
11
+ */
12
+
13
+ import type {
14
+ Duration, Tick, SimulationContext,
15
+ ReadonlySimulationState, StateCommands, SimulationEvent,
16
+ } from '#core/types'
17
+ // import type { ExecutiveEngine } from '#faculties/executive.engine'
18
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
19
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
20
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
21
+ import { GenerativeModel } from '#cognition/generative.model'
22
+ import { readEffectiveParams } from '#cognition/persona.prior'
23
+ import { ExecutiveEngine } from './executive.engine'
24
+
25
+ export interface IntrospectionEngineConfig {
26
+ cooldownTicks?: number
27
+ significanceThreshold?: number
28
+ bus?: CognitiveBus
29
+ }
30
+
31
+ export interface IntrospectionResult {
32
+ question: string
33
+ explanation: string
34
+ identifiedBiases: string[]
35
+ lessons: string[]
36
+ introspectedAt: Tick
37
+ analyzedTicks: Tick[]
38
+ }
39
+
40
+ export class IntrospectionEngine implements SimulationEngine, CognitiveEngine {
41
+ readonly name = 'introspection-engine'
42
+
43
+ private _cooldownTicks: number
44
+ private _significanceThreshold: number
45
+
46
+ private _lastIntrospectionTick: number = -100
47
+ private _introspectionHistory: IntrospectionResult[] = []
48
+ private _emittedEntityIds: string[] = []
49
+ private _executiveEngine: ExecutiveEngine | null = null
50
+
51
+ private _affectArousal: number = 0.3
52
+
53
+ private _bus: CognitiveBus | null = null
54
+
55
+ private readonly _model = new GenerativeModel()
56
+
57
+
58
+ constructor( config: IntrospectionEngineConfig = {} ){
59
+ this._bus = config.bus ?? null
60
+ this._cooldownTicks = config.cooldownTicks ?? 50
61
+ this._significanceThreshold = config.significanceThreshold ?? 0.4
62
+ }
63
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
64
+
65
+ attachExecutiveEngine( oe: ExecutiveEngine ): void {
66
+ this._executiveEngine = oe
67
+ }
68
+
69
+ subscribes(): string[] { return ["affect.state.changed","executive.prediction.formed"] }
70
+ publishes(): CognitiveEventSchema[] { return [] }
71
+
72
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
73
+ this._model.observe( e.type, e.salience )
74
+ switch( e.type ){
75
+ case 'affect.state.changed':
76
+ this._affectArousal = (e.payload as Record<string,number>)['arousal'] ?? this._affectArousal
77
+ break
78
+ case 'executive.prediction.formed': {
79
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
80
+ if (p.predictedDomains.includes('metacognition'))
81
+ this._model.setPrecision('introspection.significance', 1.0 + p.confidence * 0.5)
82
+ break
83
+ }
84
+ }
85
+ }
86
+
87
+ snapshot(): Record<string, unknown> {
88
+ return {
89
+ affectArousal: this._affectArousal,
90
+ }
91
+ }
92
+
93
+ async react(
94
+ _delta: Duration,
95
+ tick: Tick,
96
+ state: ReadonlySimulationState,
97
+ context: SimulationContext
98
+ ): Promise<EngineResult> {
99
+ const events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = []
100
+ const commands: StateCommands = { set: [], metrics: [] }
101
+
102
+ // Effective config = base ⊕ persona-prior. Closes the bias → introspection
103
+ // edge: when the consolidator lowers cooldownTicks (recurring bias), the Will
104
+ // introspects more often.
105
+ this._readConfigFromState( state )
106
+
107
+ // Did this tick actually produce an introspection, and how substantive was
108
+ // it? This is the surprise signal — replaces the every-tick publish gated on
109
+ // a monotonic history count (which never read as surprising once it grew).
110
+ let introspectedThisTick = false
111
+ let significance = 0
112
+
113
+ // Try executive output first
114
+ const executiveOutput = this._executiveEngine?.latestOutput
115
+
116
+ if( executiveOutput?.introspection && this._executiveEngine?.isFresh( tick ) ){
117
+ const result: IntrospectionResult = {
118
+ question: 'Executive introspection',
119
+ explanation: executiveOutput.introspection.explanation,
120
+ identifiedBiases: executiveOutput.introspection.identifiedBiases,
121
+ lessons: executiveOutput.introspection.lessonsLearned,
122
+ introspectedAt: tick,
123
+ analyzedTicks: [ tick ],
124
+ }
125
+
126
+ this._introspectionHistory.push( result )
127
+ if( this._introspectionHistory.length > 50 )
128
+ this._introspectionHistory = this._introspectionHistory.slice( -30 )
129
+
130
+ const entityId = `introspection-executive-${tick}`
131
+ this._emittedEntityIds.push( entityId )
132
+ commands.set!.push({
133
+ id: entityId,
134
+ type: 'introspection',
135
+ metadata: {
136
+ question: result.question,
137
+ explanation: result.explanation,
138
+ identifiedBiases: result.identifiedBiases,
139
+ lessons: result.lessons,
140
+ source: 'executive',
141
+ },
142
+ })
143
+
144
+ introspectedThisTick = true
145
+ significance = result.identifiedBiases.length + result.lessons.length
146
+ commands.metrics!.push([ 'introspection.source', 1 ])
147
+ }
148
+ else if( this._shouldHeuristicIntrospect( state, tick ) ){
149
+ const result = this._heuristicIntrospection( state, tick )
150
+
151
+ this._introspectionHistory.push( result )
152
+ if( this._introspectionHistory.length > 50 )
153
+ this._introspectionHistory = this._introspectionHistory.slice( -30 )
154
+
155
+ const entityId = `introspection-heuristic-${tick}`
156
+ this._emittedEntityIds.push( entityId )
157
+ commands.set!.push({
158
+ id: entityId,
159
+ type: 'introspection',
160
+ metadata: {
161
+ question: result.question,
162
+ explanation: result.explanation,
163
+ identifiedBiases: result.identifiedBiases,
164
+ lessons: result.lessons,
165
+ source: 'heuristic',
166
+ },
167
+ })
168
+
169
+ introspectedThisTick = true
170
+ significance = result.identifiedBiases.length + result.lessons.length
171
+ commands.metrics!.push([ 'introspection.source', 0 ])
172
+ }
173
+
174
+ // Prune old entities
175
+ if( this._emittedEntityIds.length > 10 ){
176
+ commands.delete = this._emittedEntityIds.splice( 0, this._emittedEntityIds.length - 10 )
177
+ }
178
+
179
+ commands.metrics!.push([ 'introspection.total', this._introspectionHistory.length ])
180
+
181
+ // Phase C: publish a cognitive event only when this tick actually
182
+ // introspected. Salience rides the `introspection.significance` stream —
183
+ // the same stream the executive's precision knob targets (they were
184
+ // mismatched: precision set on .significance, salience read off .total).
185
+ const _bus = this._bus
186
+ if( _bus && introspectedThisTick )
187
+ _bus.publish({ type: 'introspection.insight', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, this._model.observe( 'introspection.significance', significance ).salience ), payload: { total: this._introspectionHistory.length, significance } })
188
+ return { events: events.length > 0 ? events : undefined, commands }
189
+ }
190
+
191
+ private _shouldHeuristicIntrospect( state: ReadonlySimulationState, tick: Tick ): boolean {
192
+ if( tick - this._lastIntrospectionTick < this._cooldownTicks ) return false
193
+ const significance = state.metrics.get('outcome.significance') ?? 0
194
+ return significance > this._significanceThreshold
195
+ }
196
+
197
+ private _heuristicIntrospection( state: ReadonlySimulationState, tick: Tick ): IntrospectionResult {
198
+ // Reflect on biases ALREADY detected by bias.detector (the single detection authority)
199
+ // rather than re-detecting them here — introspection turns them into lessons. (High
200
+ // arousal is an in-the-moment reflection on emotional influence, not a stored bias, so
201
+ // that observation stays.)
202
+ const detectedBiases: string[] = []
203
+ for( const entity of state.entities.values() )
204
+ if( entity.type === 'cognitive_bias' )
205
+ detectedBiases.push(
206
+ ( entity.metadata?.description as string )
207
+ ?? ( entity.metadata?.type as string )
208
+ ?? 'a cognitive bias'
209
+ )
210
+
211
+ const lessons: string[] = []
212
+ if( detectedBiases.length > 0 )
213
+ lessons.push('Be aware of these biases when making high-confidence decisions')
214
+
215
+ const arousal = this._affectArousal
216
+ if( arousal > 0.6 )
217
+ lessons.push('Consider pausing deliberation when highly aroused')
218
+
219
+ this._lastIntrospectionTick = tick
220
+
221
+ return {
222
+ question: 'What patterns are present in my recent reasoning?',
223
+ explanation: `Reflected on ${detectedBiases.length} bias(es) detected this period.`,
224
+ identifiedBiases: detectedBiases,
225
+ lessons,
226
+ introspectedAt: tick,
227
+ analyzedTicks: [],
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Effective config = base engine-config ⊕ persona-prior. The consolidator
233
+ * lowers `cooldownTicks` when bias is recurring, so introspection runs more
234
+ * often. (The seeded base matches this engine's defaults — no single-source
235
+ * drift — so reading base⊕prior is safe here.)
236
+ */
237
+ private _readConfigFromState( state: ReadonlySimulationState ): void {
238
+ const p = readEffectiveParams( state, 'engine-config-introspection' )
239
+ if( p.cooldownTicks != null ) this._cooldownTicks = p.cooldownTicks
240
+ if( p.significanceThreshold != null ) this._significanceThreshold = p.significanceThreshold
241
+ }
242
+
243
+ getHistory(): ReadonlyArray<IntrospectionResult> {
244
+ return this._introspectionHistory
245
+ }
246
+ }