@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,333 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/theory.of.mind.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * TheoryOfMind — models what other agents know, believe, and intend.
7
+ *
8
+ * Maintains a mental model for each observed agent:
9
+ * - Knowledge state (what they've observed)
10
+ * - Belief state (what they think is true, may differ from reality)
11
+ * - Intention state (what they're trying to achieve)
12
+ * - Emotional state (what they're likely feeling)
13
+ *
14
+ * Updates models based on:
15
+ * - Observed actions (what the other agent did)
16
+ * - Shared observations (what the other agent could have seen)
17
+ * - Communication (what the other agent explicitly shared)
18
+ *
19
+ * Part of Shard 1 (Social Layer) — runs every tick, synchronous.
20
+ */
21
+
22
+ import type {
23
+ Duration,
24
+ Tick,
25
+ SimulationContext,
26
+ ReadonlySimulationState,
27
+ StateCommands,
28
+ SimulationEvent,
29
+ } from '#core/types'
30
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
31
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
32
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
33
+ import { GenerativeModel } from '#cognition/generative.model'
34
+
35
+ export interface TheoryOfMindConfig {
36
+ /** Maximum agents to model simultaneously */
37
+ maxModeledAgents?: number
38
+ /** How quickly belief confidence decays without observation */
39
+ beliefDecayRate?: number
40
+ /** Minimum confidence to consider a belief reliable */
41
+ confidenceThreshold?: number
42
+ bus?: CognitiveBus
43
+ }
44
+
45
+ export interface AgentMentalModel {
46
+ keid: string
47
+ /** What this agent is known to have observed */
48
+ knownObservations: Array<{ entityId: string; tick: Tick; confidence: number }>
49
+ /** What this agent is believed to believe */
50
+ beliefs: Array<{ statement: string; confidence: number; lastUpdated: Tick }>
51
+ /** What this agent is believed to intend */
52
+ intentions: Array<{ goal: string; confidence: number; lastUpdated: Tick }>
53
+ /** What this agent is likely feeling */
54
+ emotionalState: { valence: number; arousal: number; dominantEmotion: string }
55
+ /** Last tick this model was updated */
56
+ lastUpdated: Tick
57
+ /** Overall model confidence */
58
+ modelConfidence: number
59
+ }
60
+
61
+ export class TheoryOfMind implements SimulationEngine, CognitiveEngine {
62
+ readonly name = 'theory-of-mind'
63
+
64
+ private _maxModeledAgents: number
65
+ private _beliefDecayRate: number
66
+ private _confidenceThreshold: number
67
+
68
+ private _models = new Map<string, AgentMentalModel>()
69
+ private _restored = false
70
+ private _pendingInteractions: Array<{
71
+ keid: string; valence: number; intensity: number
72
+ directedAtSelf: boolean; interactionType: string
73
+ }> = []
74
+
75
+ private _bus: CognitiveBus | null = null
76
+
77
+ private readonly _model = new GenerativeModel()
78
+
79
+
80
+ constructor( config: TheoryOfMindConfig = {} ){
81
+ this._bus = config.bus ?? null
82
+ this._maxModeledAgents = config.maxModeledAgents ?? 10
83
+ this._beliefDecayRate = config.beliefDecayRate ?? 0.002
84
+ this._confidenceThreshold = config.confidenceThreshold ?? 0.3
85
+ }
86
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
87
+
88
+ // ── Engine interface ─────────────────────────────────────
89
+
90
+ subscribes(): string[] {
91
+ return [
92
+ 'executive.prediction.formed',
93
+ 'interaction.occurred',
94
+ ]
95
+ }
96
+
97
+ publishes(): CognitiveEventSchema[] { return [] }
98
+
99
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
100
+ this._model.observe( e.type, e.salience )
101
+ if( e.type === 'executive.prediction.formed' ){
102
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
103
+ if( p.predictedDomains.includes('social') )
104
+ this._model.setPrecision( 'tom.models', 1.0 + p.confidence * 0.5 )
105
+ }
106
+ if( e.type === 'interaction.occurred' ){
107
+ const p = e.payload as {
108
+ keid: string; valence: number; intensity: number
109
+ directedAtSelf: boolean; interactionType: string
110
+ }
111
+ if( p.keid && p.keid !== 'agent-self' )
112
+ this._pendingInteractions.push( p )
113
+ }
114
+ }
115
+
116
+ snapshot(): Record<string, unknown> { return {} }
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: [], delete: [], metrics: [] }
127
+
128
+ // On the first tick after construction (including snapshot/PMA restores), rehydrate
129
+ // _models from the persisted tom-<id> gist — parity with attachment/reputation, which
130
+ // already restore. Without this a restored Will keeps its bonds + trust but loses the
131
+ // effector to *model* those same minds (empathy.getModel returns nothing; maintenance
132
+ // stalls). The entity only ever stored a gist, so the restore is gist-level by design.
133
+ if( !this._restored ){
134
+ this._restoreFromState( state )
135
+ this._restored = true
136
+ }
137
+
138
+ // Drain pending interactions buffered from interaction.occurred events
139
+ const interactions = this._pendingInteractions.splice( 0 )
140
+ for( const interaction of interactions ){
141
+ const model = this._getOrCreateModel( interaction.keid, tick )
142
+ const action = interaction.interactionType
143
+
144
+ model.knownObservations.push({
145
+ entityId: `action-${action}-${tick}`,
146
+ tick,
147
+ confidence: 0.8,
148
+ })
149
+
150
+ this._inferIntention( model, action, tick )
151
+
152
+ model.emotionalState = {
153
+ valence: interaction.valence > 0.3 ? 0.5 : interaction.valence < -0.3 ? -0.5 : 0,
154
+ arousal: Math.abs( interaction.valence ) > 0.5 ? 0.7 : 0.3,
155
+ dominantEmotion: interaction.valence > 0.3 ? 'satisfaction' : interaction.valence < -0.3 ? 'frustration' : 'neutral',
156
+ }
157
+
158
+ model.lastUpdated = tick
159
+ }
160
+
161
+ // 3. Decay old beliefs
162
+ this._decayBeliefs( tick )
163
+
164
+ // 4. Prune models with low confidence
165
+ this._pruneModels()
166
+
167
+ // 5. Persist models
168
+ for( const [ keid, model ] of this._models ){
169
+ commands.set!.push({
170
+ id: `tom-${keid}`,
171
+ type: 'theory_of_mind',
172
+ createdAt: model.lastUpdated,
173
+ updatedAt: tick,
174
+ metadata: {
175
+ keid,
176
+ beliefCount: model.beliefs.filter( b => b.confidence > this._confidenceThreshold ).length,
177
+ intentionCount: model.intentions.filter( i => i.confidence > this._confidenceThreshold ).length,
178
+ modelConfidence: model.modelConfidence,
179
+ dominantIntention: model.intentions
180
+ .sort( ( a, b ) => b.confidence - a.confidence )[0]?.goal ?? null,
181
+ estimatedEmotion: model.emotionalState.dominantEmotion,
182
+ },
183
+ })
184
+ }
185
+
186
+ commands.metrics!.push(
187
+ [ 'theory_of_mind.models_active', this._models.size ],
188
+ )
189
+
190
+
191
+ // Phase C + F: publish cognitive event — gated by prediction error
192
+ const _bus = this._bus
193
+ if( _bus && this._models.size > 0 ){
194
+ const predErr = this._model.observe( 'tom.models', this._models.size )
195
+ if( !predErr.gated )
196
+ _bus.publish({ type: 'theory_of_mind.model.updated', version: 1, sourceEngine: this.name, salience: Math.max( 0.2, predErr.salience ), payload: { modelsActive: this._models.size } })
197
+ }
198
+ return { events: events.length > 0 ? events : undefined, commands }
199
+ }
200
+
201
+ // ── Public API ───────────────────────────────────────────
202
+
203
+ /**
204
+ * Query what another agent is likely to know/believe/intend.
205
+ */
206
+ getModel( keid: string ): AgentMentalModel | undefined {
207
+ return this._models.get( keid )
208
+ }
209
+
210
+ /**
211
+ * Check if another agent is likely aware of something.
212
+ */
213
+ isLikelyAwareOf( keid: string, entityId: string ): boolean {
214
+ const model = this._models.get( keid )
215
+ if( !model ) return false
216
+
217
+ return model.knownObservations.some(
218
+ o => o.entityId === entityId && o.confidence > this._confidenceThreshold
219
+ )
220
+ }
221
+
222
+ // ── Internal ─────────────────────────────────────────────
223
+
224
+ /**
225
+ * Rehydrate _models from persisted tom-<id> entities on the first tick after a
226
+ * snapshot/PMA restore — mirrors AttachmentEvaluator/ReputationTracker._restoreFromState.
227
+ * The entity stores a gist (modelConfidence + the dominant intention + estimated emotion),
228
+ * not the full belief/observation arrays, so the restored model is a coherent gist that
229
+ * subsequent interactions grow from — the soul-true level: you recover your *sense* of a
230
+ * mind, not every belief you once inferred about it.
231
+ */
232
+ private _restoreFromState( state: ReadonlySimulationState ): void {
233
+ for( const entity of state.entities.values() ){
234
+ if( entity.type !== 'theory_of_mind' ) continue
235
+ const m = entity.metadata ?? {}
236
+ const keid = m['keid'] as string | undefined
237
+ if( !keid ) continue
238
+ if( this._models.has( keid ) ) continue // prefer a live model if already present
239
+
240
+ const dominantIntention = ( m['dominantIntention'] as string | null ) ?? null
241
+ const modelConfidence = ( m['modelConfidence'] as number ) ?? 0.3
242
+ const estimatedEmotion = ( m['estimatedEmotion'] as string ) ?? 'neutral'
243
+
244
+ this._models.set( keid, {
245
+ keid,
246
+ knownObservations: [],
247
+ beliefs: [],
248
+ intentions: dominantIntention
249
+ ? [ { goal: dominantIntention, confidence: modelConfidence, lastUpdated: 0 as unknown as Tick } ]
250
+ : [],
251
+ emotionalState: { valence: 0, arousal: 0, dominantEmotion: estimatedEmotion },
252
+ lastUpdated: 0 as unknown as Tick,
253
+ modelConfidence,
254
+ })
255
+ }
256
+ }
257
+
258
+ private _getOrCreateModel( keid: string, tick: Tick ): AgentMentalModel {
259
+ const existing = this._models.get( keid )
260
+ if( existing ) return existing
261
+
262
+ const model: AgentMentalModel = {
263
+ keid,
264
+ knownObservations: [],
265
+ beliefs: [],
266
+ intentions: [],
267
+ emotionalState: { valence: 0, arousal: 0.3, dominantEmotion: 'neutral' },
268
+ lastUpdated: tick,
269
+ modelConfidence: 0.3,
270
+ }
271
+
272
+ this._models.set( keid, model )
273
+ return model
274
+ }
275
+
276
+ private _inferIntention(
277
+ model: AgentMentalModel,
278
+ action: string,
279
+ tick: Tick
280
+ ): void {
281
+ const existingIntention = model.intentions.find( i => i.goal === action )
282
+
283
+ if( existingIntention ){
284
+ existingIntention.confidence = Math.min( 1, existingIntention.confidence + 0.1 )
285
+ existingIntention.lastUpdated = tick
286
+ }
287
+ else model.intentions.push({
288
+ goal: action,
289
+ confidence: 0.4,
290
+ lastUpdated: tick,
291
+ })
292
+
293
+ // Boost overall model confidence
294
+ model.modelConfidence = Math.min( 1, model.modelConfidence + 0.02 )
295
+ }
296
+
297
+ private _decayBeliefs( currentTick: Tick ): void {
298
+ for( const model of this._models.values() ){
299
+ const ticksSinceUpdate = currentTick - model.lastUpdated
300
+
301
+ if( ticksSinceUpdate > 100 ){
302
+ model.modelConfidence = Math.max( 0.05, model.modelConfidence - this._beliefDecayRate * ticksSinceUpdate )
303
+
304
+ for( const belief of model.beliefs )
305
+ belief.confidence = Math.max( 0.05, belief.confidence - this._beliefDecayRate * 2 )
306
+
307
+ for( const intention of model.intentions )
308
+ intention.confidence = Math.max( 0.05, intention.confidence - this._beliefDecayRate * 2 )
309
+ }
310
+ }
311
+ }
312
+
313
+ private _pruneModels(): void {
314
+ const toPrune: string[] = []
315
+
316
+ for( const [ id, model ] of this._models ){
317
+ if( model.modelConfidence < 0.05 )
318
+ toPrune.push( id )
319
+ }
320
+
321
+ for( const id of toPrune )
322
+ this._models.delete( id )
323
+
324
+ // Also prune if over capacity — keep highest confidence
325
+ if( this._models.size > this._maxModeledAgents ){
326
+ const sorted = Array.from( this._models.entries() )
327
+ .sort( ( a, b ) => b[1].modelConfidence - a[1].modelConfidence )
328
+
329
+ for( const [ id ] of sorted.slice( this._maxModeledAgents ) )
330
+ this._models.delete( id )
331
+ }
332
+ }
333
+ }
@@ -0,0 +1,312 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/threat.evaluator.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * ThreatEvaluator — assesses danger across multiple dimensions.
7
+ *
8
+ * Evaluates:
9
+ * - Hostile entities (entities marked as threatening)
10
+ * - Resource scarcity (low energy, time pressure)
11
+ * - Uncertainty (high novelty, low predictability)
12
+ * - Social rejection risk (negative social signals directed at self)
13
+ *
14
+ * Produces: fear, anxiety, vigilance
15
+ *
16
+ * Fear = immediate, identifiable threat
17
+ * Anxiety = diffuse, uncertain threat
18
+ * Vigilance = heightened alertness in response to elevated threat level
19
+ *
20
+ * Part of Shard 1 (Affective Layer) — runs every tick, synchronous.
21
+ */
22
+
23
+ import type {
24
+ StateCommands,
25
+ Duration,
26
+ Tick,
27
+ ReadonlySimulationState,
28
+ SimulationContext,
29
+ } from '#core/types'
30
+ import type { EngineResult } from '#core/orchestrator'
31
+ import type { SimulationEngine, 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
+ import { readEffectiveParams } from '#cognition/persona.prior'
36
+
37
+ export interface ThreatEvaluatorConfig {
38
+ /** Weight for hostile entity threats */
39
+ hostileWeight?: number
40
+ /** Weight for resource scarcity threats */
41
+ scarcityWeight?: number
42
+ /** Weight for uncertainty threats */
43
+ uncertaintyWeight?: number
44
+ /** Weight for social rejection threats */
45
+ socialWeight?: number
46
+ /** Threshold above which fear triggers a significant event */
47
+ fearEventThreshold?: number
48
+ bus?: CognitiveBus
49
+ }
50
+
51
+ export class ThreatEvaluator implements SimulationEngine, CognitiveEngine {
52
+ readonly name = 'threat-evaluator'
53
+
54
+ private _hostileWeight: number
55
+ private _scarcityWeight: number
56
+ private _uncertaintyWeight: number
57
+ private _socialWeight: number
58
+ private _fearEventThreshold: number
59
+
60
+ // Domain state — updated per-event
61
+ private _energyLevel: number = 100
62
+ private _sleepPressure: number = 0
63
+ private _stressLoad: number = 0
64
+ private _deadlineUrgency: number = 0
65
+ private _cognitiveLoad: number = 0
66
+ private _cachedNovelty: number = 0
67
+ private _cachedMetacognitionConfidence: number = 0.7
68
+ private _socialEvaluationThreat: number = 0
69
+ private _activeAgents: number = 0
70
+
71
+ // Cached component threats — accumulated across events
72
+ private _threatFromHostile: number = 0 // updated only if entity events are added
73
+ private _threatFromScarcity: number = 0
74
+ private _threatFromUncertainty: number = 0
75
+ private _threatFromSocial: number = 0
76
+
77
+ private _bus: CognitiveBus | null = null
78
+
79
+ private readonly _model = new GenerativeModel()
80
+
81
+
82
+ constructor( config: ThreatEvaluatorConfig = {} ){
83
+ this._bus = config.bus ?? null
84
+ this._hostileWeight = config.hostileWeight ?? 0.35
85
+ this._scarcityWeight = config.scarcityWeight ?? 0.25
86
+ this._uncertaintyWeight = config.uncertaintyWeight ?? 0.20
87
+ this._socialWeight = config.socialWeight ?? 0.20
88
+ this._fearEventThreshold = config.fearEventThreshold ?? 0.6
89
+ }
90
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
91
+
92
+ // ── Engine interface ─────────────────────────────────────
93
+
94
+ subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","stress.state.changed","novelty.state.changed","metacognition.state.changed","executive.prediction.formed"] }
95
+ publishes(): CognitiveEventSchema[] { return [] }
96
+
97
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
98
+ this._model.observe( e.type, e.salience )
99
+
100
+ switch( e.type ){
101
+
102
+ case 'energy.state.changed': {
103
+ const p = e.payload as { level: number }
104
+ this._energyLevel = p.level ?? this._energyLevel
105
+ this._threatFromScarcity = this._computeScarcityThreat()
106
+ break
107
+ }
108
+
109
+ case 'sleep.state.changed': {
110
+ const p = e.payload as { pressure: number }
111
+ this._sleepPressure = p.pressure ?? this._sleepPressure
112
+ this._threatFromScarcity = this._computeScarcityThreat()
113
+ break
114
+ }
115
+
116
+ case 'stress.state.changed': {
117
+ const p = e.payload as { load: number; deadlineUrgency: number; cognitiveLoad: number }
118
+ this._stressLoad = p.load ?? this._stressLoad
119
+ this._deadlineUrgency = p.deadlineUrgency ?? this._deadlineUrgency
120
+ this._cognitiveLoad = p.cognitiveLoad ?? this._cognitiveLoad
121
+ this._threatFromScarcity = this._computeScarcityThreat()
122
+ this._threatFromUncertainty = this._computeUncertaintyThreat()
123
+ break
124
+ }
125
+
126
+ case 'novelty.state.changed': {
127
+ const p = e.payload as { novelty: number; socialEvaluationThreat: number; activeAgents: number; fearLevel: number }
128
+ this._cachedNovelty = p.novelty ?? this._cachedNovelty
129
+ this._socialEvaluationThreat = p.socialEvaluationThreat ?? this._socialEvaluationThreat
130
+ this._activeAgents = p.activeAgents ?? this._activeAgents
131
+ this._threatFromUncertainty = this._computeUncertaintyThreat()
132
+ this._threatFromSocial = this._computeSocialThreat()
133
+ break
134
+ }
135
+
136
+ case 'metacognition.state.changed': {
137
+ const p = e.payload as { confidence: number }
138
+ this._cachedMetacognitionConfidence = p.confidence ?? this._cachedMetacognitionConfidence
139
+ this._threatFromUncertainty = this._computeUncertaintyThreat()
140
+ break
141
+ }
142
+
143
+ case 'executive.prediction.formed': {
144
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
145
+ if( p.predictedDomains.includes('social') )
146
+ this._model.setPrecision('threat.level', 1.0 + p.confidence * 0.4)
147
+ break
148
+ }
149
+
150
+ default:
151
+ return
152
+ }
153
+
154
+ return this._computeAndEmit()
155
+ }
156
+
157
+ snapshot(): Record<string, unknown> {
158
+ return {
159
+ energyLevel: this._energyLevel,
160
+ sleepPressure: this._sleepPressure,
161
+ stressLoad: this._stressLoad,
162
+ }
163
+ }
164
+
165
+ // ── React (state scan) ────────────────────────────────────
166
+
167
+ /**
168
+ * Scans state each tick for active hostile entities (type === 'threat',
169
+ * metadata.hostile === true). Updates _threatFromHostile and re-emits
170
+ * the full threat/emotion metrics so that downstream engines always see
171
+ * a current picture even when no bus event arrives.
172
+ */
173
+ async react(
174
+ _delta: Duration,
175
+ _tick: Tick,
176
+ state: ReadonlySimulationState,
177
+ _context: SimulationContext,
178
+ ): Promise<EngineResult> {
179
+ // Channel A (emotional-stability): how much threat it takes to fire a significant-fear
180
+ // event is refreshed each tick as base ⊕ persona-prior, so a steadier Will develops a
181
+ // HIGHER threshold and is less easily alarmed. _computeAndEmit (no `state`) reads the
182
+ // cached field. (The seed entity existed but was ignored before.)
183
+ this._fearEventThreshold = readEffectiveParams( state, 'engine-config-threat' ).fearEventThreshold ?? this._fearEventThreshold
184
+
185
+ // Recompute hostile threat from state entities every tick
186
+ let maxHostile = 0
187
+ for( const entity of state.entities.values() ){
188
+ if( entity.type !== 'threat' ) continue
189
+ if( entity.metadata?.active === false ) continue
190
+ if( !entity.metadata?.hostile ) continue
191
+ const intensity = typeof entity.metadata?.intensity === 'number'
192
+ ? entity.metadata.intensity as number
193
+ : 0.5
194
+ if( intensity > maxHostile ) maxHostile = intensity
195
+ }
196
+ this._threatFromHostile = maxHostile
197
+
198
+ const commands = this._computeAndEmit()
199
+ return { commands }
200
+ }
201
+
202
+ // ── Private helpers ──────────────────────────────────────
203
+
204
+ private _computeScarcityThreat(): number {
205
+ const
206
+ energyThreat = Math.max( 0, 1 - this._energyLevel / ( 100 * 0.3 ) ),
207
+ timeThreat = this._deadlineUrgency,
208
+ sleepThreat = this._sleepPressure > 70 ? ( this._sleepPressure - 70 ) / 30 : 0
209
+
210
+ return Math.min( 1,
211
+ energyThreat * 0.4
212
+ + timeThreat * 0.35
213
+ + sleepThreat * 0.25
214
+ )
215
+ }
216
+
217
+ private _computeUncertaintyThreat(): number {
218
+ const
219
+ novelty = this._cachedNovelty,
220
+ confidence = this._cachedMetacognitionConfidence,
221
+ unpredictability = novelty * ( 1 - confidence ),
222
+ cognitiveLoad = this._cognitiveLoad
223
+
224
+ return Math.min( 1,
225
+ unpredictability * 0.6
226
+ + ( cognitiveLoad > 0.8 ? 0.3 : 0 )
227
+ + ( novelty > 0.7 ? 0.1 : 0 )
228
+ )
229
+ }
230
+
231
+ private _computeSocialThreat(): number {
232
+ const
233
+ evaluationThreat = this._socialEvaluationThreat,
234
+ socialIsolation = this._activeAgents < 1 ? 0.4 : 0
235
+
236
+ return Math.min( 1,
237
+ evaluationThreat * 0.5
238
+ + socialIsolation * 0.15
239
+ )
240
+ }
241
+
242
+ private _computeAndEmit(): StateCommands {
243
+ const
244
+ hostileThreat = this._threatFromHostile,
245
+ scarcityThreat = this._threatFromScarcity,
246
+ uncertaintyThreat = this._threatFromUncertainty,
247
+ socialThreat = this._threatFromSocial
248
+
249
+ const threatLevel
250
+ = hostileThreat * this._hostileWeight
251
+ + scarcityThreat * this._scarcityWeight
252
+ + uncertaintyThreat * this._uncertaintyWeight
253
+ + socialThreat * this._socialWeight
254
+
255
+ const
256
+ fear = Math.min( 1,
257
+ hostileThreat * 0.7
258
+ + socialThreat * 0.2
259
+ + ( scarcityThreat > 0.7 ? 0.1 : 0 )
260
+ ),
261
+
262
+ anxiety = Math.min( 1,
263
+ uncertaintyThreat * 0.5
264
+ + ( threatLevel - fear ) * 0.5
265
+ + ( socialThreat > 0.3 && hostileThreat < 0.4 ? 0.3 : 0 )
266
+ ),
267
+
268
+ vigilance = Math.min( 1, threatLevel * 1.2 )
269
+
270
+ const commands: StateCommands = { metrics: [] }
271
+
272
+ commands.metrics!.push(
273
+ [ 'emotion.fear', fear ],
274
+ [ 'emotion.anxiety', anxiety ],
275
+ [ 'emotion.vigilance', vigilance ],
276
+ [ 'threat.level', threatLevel ],
277
+ [ 'threat.hostile', hostileThreat ],
278
+ [ 'threat.scarcity', scarcityThreat ],
279
+ [ 'threat.uncertainty', uncertaintyThreat ],
280
+ [ 'threat.social', socialThreat ],
281
+ )
282
+
283
+ const _bus = this._bus
284
+ if( _bus ){
285
+ // Option B (predictive-processing): event salience is surprise × precision,
286
+ // not raw magnitude. A CHANGE in threat grabs the workspace; a steady threat
287
+ // habituates (its level still rides the executive's standing context — see
288
+ // worldState.threatLevel). observe() runs every tick so the baseline tracks
289
+ // and the executive's top-down precision (set on 'threat.level') applies;
290
+ // the one value is reused across the tiered events.
291
+ const threatSalience = this._model.observe( 'threat.level', threatLevel ).salience
292
+
293
+ if( fear > 0.4 )
294
+ _bus.publish({ type: 'emotion.fear.elevated', version: 1, sourceEngine: this.name, salience: threatSalience, payload: { fear } })
295
+ if( fear > this._fearEventThreshold )
296
+ _bus.publish({
297
+ type: 'emotion.fear.significant', version: 1, sourceEngine: this.name,
298
+ salience: threatSalience,
299
+ payload: {
300
+ fear, anxiety, vigilance, threatLevel,
301
+ dominantThreat: hostileThreat > scarcityThreat
302
+ ? ( hostileThreat > socialThreat ? 'hostile' : 'social')
303
+ : ( scarcityThreat > uncertaintyThreat ? 'scarcity' : 'uncertainty'),
304
+ },
305
+ })
306
+ if( anxiety > 0.7 )
307
+ _bus.publish({ type: 'emotion.anxiety.elevated', version: 1, sourceEngine: this.name, salience: threatSalience, payload: { anxiety, uncertaintyThreat } })
308
+ }
309
+
310
+ return commands
311
+ }
312
+ }