@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.
- package/LICENSE +202 -0
- package/README.md +777 -0
- package/dist/index.d.ts +8144 -0
- package/dist/index.js +26231 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
- package/src/cognition/agency/access.grants.ts +59 -0
- package/src/cognition/agency/competence.codec.ts +89 -0
- package/src/cognition/agency/engines/action.selector.ts +462 -0
- package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
- package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
- package/src/cognition/agency/engines/instruction.intake.ts +54 -0
- package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
- package/src/cognition/agency/engines/reafference.engine.ts +241 -0
- package/src/cognition/agency/execution.primitives.ts +118 -0
- package/src/cognition/agency/index.ts +58 -0
- package/src/cognition/agency/proactive.communicator.ts +274 -0
- package/src/cognition/agency/reconcile.learning.ts +82 -0
- package/src/cognition/agency/schemas/external.ts +59 -0
- package/src/cognition/agency/schemas/innate.ts +111 -0
- package/src/cognition/agency/schemas/repertoire.ts +246 -0
- package/src/cognition/agency/selection.scoring.ts +191 -0
- package/src/cognition/agency/types.ts +165 -0
- package/src/cognition/bus.ts +391 -0
- package/src/cognition/completion.inbox.ts +86 -0
- package/src/cognition/config.mirror.entities.ts +475 -0
- package/src/cognition/conversation.memory.ts +81 -0
- package/src/cognition/event.log.ts +116 -0
- package/src/cognition/event.schemas.ts +568 -0
- package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
- package/src/cognition/faculties/affective.blender.ts +562 -0
- package/src/cognition/faculties/attachment.evaluator.ts +432 -0
- package/src/cognition/faculties/attention.allocator.ts +422 -0
- package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
- package/src/cognition/faculties/bias.detector.ts +363 -0
- package/src/cognition/faculties/circadian.oscillator.ts +294 -0
- package/src/cognition/faculties/confidence.calibrator.ts +324 -0
- package/src/cognition/faculties/dream.simulator.ts +251 -0
- package/src/cognition/faculties/empathy.simulator.ts +253 -0
- package/src/cognition/faculties/energy.regulator.ts +320 -0
- package/src/cognition/faculties/episodic.consolidator.ts +728 -0
- package/src/cognition/faculties/executive.engine/commands.ts +459 -0
- package/src/cognition/faculties/executive.engine/config.ts +46 -0
- package/src/cognition/faculties/executive.engine/context.ts +605 -0
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
- package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
- package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
- package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
- package/src/cognition/faculties/executive.engine/facet.ts +628 -0
- package/src/cognition/faculties/executive.engine/gating.ts +222 -0
- package/src/cognition/faculties/executive.engine/index.ts +6 -0
- package/src/cognition/faculties/executive.engine/messages.ts +102 -0
- package/src/cognition/faculties/executive.engine/parser.ts +380 -0
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
- package/src/cognition/faculties/executive.engine/types.ts +323 -0
- package/src/cognition/faculties/exteroception.ts +338 -0
- package/src/cognition/faculties/forgetting.curve.ts +202 -0
- package/src/cognition/faculties/frustration.evaluator.ts +280 -0
- package/src/cognition/faculties/goal.manager.ts +1008 -0
- package/src/cognition/faculties/inhibition.controller.ts +351 -0
- package/src/cognition/faculties/interoception.ts +417 -0
- package/src/cognition/faculties/introspection.engine.ts +246 -0
- package/src/cognition/faculties/known.entity.tracker.ts +439 -0
- package/src/cognition/faculties/loss.evaluator.ts +224 -0
- package/src/cognition/faculties/moral.evaluator.ts +437 -0
- package/src/cognition/faculties/novelty.detector.ts +254 -0
- package/src/cognition/faculties/persona.consolidator.ts +845 -0
- package/src/cognition/faculties/planning.engine/engine.ts +859 -0
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
- package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
- package/src/cognition/faculties/planning.engine/types.ts +143 -0
- package/src/cognition/faculties/reputation.tracker.ts +294 -0
- package/src/cognition/faculties/reward.evaluator.ts +304 -0
- package/src/cognition/faculties/self.model.updater.ts +677 -0
- package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
- package/src/cognition/faculties/semantic.engine/index.ts +6 -0
- package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
- package/src/cognition/faculties/semantic.engine/types.ts +53 -0
- package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
- package/src/cognition/faculties/social.perception.ts +333 -0
- package/src/cognition/faculties/spaced.repetition.ts +605 -0
- package/src/cognition/faculties/stress.regulator.ts +375 -0
- package/src/cognition/faculties/task.switcher.ts +239 -0
- package/src/cognition/faculties/theory.of.mind.ts +333 -0
- package/src/cognition/faculties/threat.evaluator.ts +312 -0
- package/src/cognition/faculties/working.memory.ts +406 -0
- package/src/cognition/generative.model.ts +344 -0
- package/src/cognition/heartbeat.ts +70 -0
- package/src/cognition/index.ts +291 -0
- package/src/cognition/instruction.handler.ts +146 -0
- package/src/cognition/memory/index.ts +35 -0
- package/src/cognition/memory/vector.adapter.ts +316 -0
- package/src/cognition/memory/vector.content.ts +47 -0
- package/src/cognition/memory/vector.embedder.ts +212 -0
- package/src/cognition/memory/vector.index.ts +459 -0
- package/src/cognition/memory/vector.types.ts +65 -0
- package/src/cognition/orchestrator.ts +142 -0
- package/src/cognition/persona.prior.ts +265 -0
- package/src/cognition/schema.registry.ts +145 -0
- package/src/cognition/senses/audition.engine/engine.ts +976 -0
- package/src/cognition/senses/audition.engine/salience.ts +59 -0
- package/src/cognition/senses/base.sense.engine.ts +117 -0
- package/src/cognition/senses/gustation.engine.ts +24 -0
- package/src/cognition/senses/index.ts +172 -0
- package/src/cognition/senses/olfaction.engine.ts +24 -0
- package/src/cognition/senses/somatosensation.engine.ts +23 -0
- package/src/cognition/senses/vision.engine.ts +23 -0
- package/src/cognition/types.ts +63 -0
- package/src/cognition/utilities/token.tracker.ts +492 -0
- package/src/core/abstracts.ts +60 -0
- package/src/core/async.engine.ts +539 -0
- package/src/core/clock.ts +196 -0
- package/src/core/completion.recorder.ts +122 -0
- package/src/core/conflict.detector.ts +140 -0
- package/src/core/distributed.ts +626 -0
- package/src/core/event.bus.ts +292 -0
- package/src/core/inbound.recorder.ts +100 -0
- package/src/core/index.ts +167 -0
- package/src/core/logger.ts +85 -0
- package/src/core/metrics.ts +107 -0
- package/src/core/orchestrator.ts +625 -0
- package/src/core/replay.ts +589 -0
- package/src/core/scenario.ts +120 -0
- package/src/core/serialization.ts +448 -0
- package/src/core/simulation.ts +197 -0
- package/src/core/snapshot.manager.ts +293 -0
- package/src/core/state.manager.ts +283 -0
- package/src/core/types.ts +274 -0
- package/src/core/utils.ts +82 -0
- package/src/core/wall.clock.ts +23 -0
- package/src/extensions/livestream.ext.ts +570 -0
- package/src/extensions/time.ext.ts +339 -0
- package/src/index.ts +91 -0
- package/src/llm/gate.ts +140 -0
- package/src/llm/index.ts +716 -0
- package/src/llm/summarizer.ts +170 -0
- package/src/llm/wire.contracts.ts +67 -0
- package/src/pma/eval.ts +651 -0
- package/src/pma/index.ts +1082 -0
- package/src/profiles/built-in.ts +7 -0
- package/src/profiles/companion.ts +28 -0
- package/src/profiles/company-brain.ts +54 -0
- package/src/profiles/customer-service.ts +30 -0
- package/src/profiles/game-npc.ts +20 -0
- package/src/profiles/index.ts +42 -0
- package/src/profiles/smart-home.ts +34 -0
- package/src/runners/coherence.runner.ts +49 -0
- package/src/runners/outreach.runner.ts +158 -0
- package/src/runners/social.runner.ts +182 -0
- package/src/runners/thin-shim.runner.ts +195 -0
- package/src/sdk/will.ts +334 -0
- package/src/stem/assembly.audit.ts +88 -0
- package/src/stem/distribution.ts +203 -0
- package/src/stem/guards/identity.coherence.ts +152 -0
- package/src/stem/guards/identity.guard.ts +227 -0
- package/src/stem/index.ts +1145 -0
- package/src/stem/mind.ts +1090 -0
- package/src/stem/tracts/ack.reconciler.ts +55 -0
- package/src/stem/tracts/biography.writer.ts +190 -0
- package/src/stem/tracts/effector.controller.ts +143 -0
- package/src/stem/tracts/health.reporter.ts +113 -0
- package/src/stem/tracts/inbound.queue.ts +54 -0
- package/src/stem/tracts/outbox.controller.ts +167 -0
- package/src/stem/tracts/outbox.writer.ts +133 -0
- package/src/stem/tracts/pma.controller.ts +109 -0
- package/src/stem/tracts/replay.controller.ts +177 -0
- package/src/stem/tracts/sensory.controller.ts +168 -0
- package/src/stem/tracts/session.logger.ts +157 -0
- package/src/stem/tracts/transport/index.ts +38 -0
- package/src/stem/tracts/transport/loopback.transport.ts +86 -0
- package/src/stem/tracts/transport/socketio.transport.ts +200 -0
- package/src/stem/tracts/transport/stream.transport.ts +152 -0
- package/src/stem/tracts/transport/types.ts +193 -0
- package/src/stem/tracts/transport.controller.ts +380 -0
- 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
|
+
}
|