@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,53 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/semantic.engine/types.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ import type { Tick } from '#core/types'
6
+ import type { CognitiveBus } from '#cognition/bus'
7
+
8
+ // Stop words to strip before text-similarity comparison.
9
+ // Keeps common filler from driving false belief merges.
10
+ export const _STOP_WORDS = new Set([
11
+ 'i','my','me','we','our','you','your','it','its',
12
+ 'the','a','an','and','or','but','in','on','at','to',
13
+ 'for','of','with','by','from','is','are','was','were',
14
+ 'be','been','being','have','has','had','do','does','did',
15
+ 'will','would','could','should','may','might','can',
16
+ 'this','that','these','those','not','no','so','as',
17
+ 'if','then','than','very','just','more','most','also',
18
+ ])
19
+
20
+ export interface SemanticIntegratorConfig {
21
+ minIntervalTicks?: number
22
+ minNewEpisodes?: number
23
+ maxBeliefs?: number
24
+ /** Ticks without reinforcement before a belief starts losing confidence */
25
+ beliefStalenessThreshold?: number
26
+ /** Confidence lost per tick once a belief goes stale */
27
+ beliefDecayRate?: number
28
+ /** Minimum similarity threshold for semantic pattern detection (0-1) */
29
+ semanticSimilarityThreshold?: number
30
+ /** Maximum episodes to query for semantic pattern detection */
31
+ semanticQueryLimit?: number
32
+ bus?: CognitiveBus
33
+ }
34
+
35
+ export interface BeliefHistoryEntry {
36
+ tick: Tick
37
+ confidence: number // confidence value after this event
38
+ delta: number // change from previous (positive = gained, negative = lost)
39
+ cause: string // 'created' | 'reinforced' | 'decayed' | 'executive' | 'heuristic' | 'self-model' | 'semantic'
40
+ }
41
+
42
+ export interface Belief {
43
+ id: string
44
+ statement: string
45
+ category: 'world_fact' | 'self_belief' | 'social_belief' | 'causal_rule' | 'pattern'
46
+ confidence: number
47
+ supportingEpisodes: number
48
+ lastUpdatedAt: Tick
49
+ tags: string[]
50
+ /** Bounded trajectory of confidence changes. Max 20 entries; oldest dropped when full.
51
+ * Becomes a first-class PMM input — the causal story of how a belief formed. */
52
+ history?: BeliefHistoryEntry[]
53
+ }
@@ -0,0 +1,262 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/sleep.pressure.regulator.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * SleepPressureRegulator — accumulates sleep drive during wakefulness
7
+ * and dissipates it during rest/sleep states.
8
+ *
9
+ * Models the two-process sleep model:
10
+ * - Process S: homeostatic sleep pressure (accumulates while awake)
11
+ * - Process C: circadian modulation (handled by CircadianOscillator)
12
+ *
13
+ * High sleep pressure degrades attention, working memory, and
14
+ * decision quality via modulation signals.
15
+ *
16
+ * Part of Shard 0 (Regulatory Layer) — runs every tick, synchronous.
17
+ */
18
+
19
+ import type {
20
+ Duration,
21
+ Tick,
22
+ SimulationContext,
23
+ ReadonlySimulationState,
24
+ StateCommands,
25
+ DriveSignal,
26
+ ModulationSignal,
27
+ SimulationEvent,
28
+ } from '#core/types'
29
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
30
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
31
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
32
+ import { GenerativeModel } from '#cognition/generative.model'
33
+
34
+ export interface SleepPressureConfig {
35
+ /** Rate at which sleep pressure accumulates while awake (per second of sim time) */
36
+ wakeAccumulationRate?: number
37
+ /** Rate at which sleep pressure dissipates during rest (per second of sim time) */
38
+ restDissipationRate?: number
39
+ /** Maximum sleep pressure (saturation point) */
40
+ maxPressure?: number
41
+ /** Pressure threshold for cognitive degradation onset */
42
+ fatigueThreshold?: number
43
+ /** Pressure threshold for severe impairment */
44
+ exhaustionThreshold?: number
45
+ bus?: CognitiveBus
46
+ }
47
+
48
+ export class SleepPressureRegulator implements SimulationEngine, CognitiveEngine {
49
+ readonly name = 'sleep-pressure-regulator'
50
+
51
+ private _wakeAccumulationRate: number
52
+ private _restDissipationRate: number
53
+ private _maxPressure: number
54
+ private _fatigueThreshold: number
55
+ private _exhaustionThreshold: number
56
+
57
+ private _wasSleeping: boolean = false
58
+
59
+ private _bus: CognitiveBus | null = null
60
+
61
+ private readonly _model = new GenerativeModel()
62
+
63
+
64
+ constructor( config: SleepPressureConfig = {} ){
65
+ this._bus = config.bus ?? null
66
+ this._wakeAccumulationRate = config.wakeAccumulationRate ?? 0.008
67
+ this._restDissipationRate = config.restDissipationRate ?? 0.04
68
+ this._maxPressure = config.maxPressure ?? 100
69
+ this._fatigueThreshold = config.fatigueThreshold ?? 40
70
+ this._exhaustionThreshold = config.exhaustionThreshold ?? 70
71
+ }
72
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
73
+
74
+ // ── Engine interface ─────────────────────────────────────
75
+
76
+
77
+ subscribes(): string[] { return ['executive.prediction.formed'] }
78
+ publishes(): CognitiveEventSchema[] {
79
+ return [
80
+ { type: 'sleep.begun', version: 1, validate: () => null },
81
+ { type: 'sleep.ended', version: 1, validate: () => null },
82
+ ]
83
+ }
84
+
85
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
86
+ this._model.observe( e.type, e.salience )
87
+ if( e.type === 'executive.prediction.formed' ){
88
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
89
+ if( p.predictedDomains.includes('interoception') )
90
+ this._model.setPrecision( 'sleep.pressure', 1.0 + p.confidence * 0.5 )
91
+ }
92
+ }
93
+
94
+ snapshot(): Record<string, unknown> { return {} }
95
+
96
+ async react(
97
+ delta: Duration,
98
+ _tick: Tick,
99
+ state: ReadonlySimulationState,
100
+ context: SimulationContext
101
+ ): Promise<EngineResult> {
102
+ this._readConfigFromState( state )
103
+
104
+ const
105
+ currentPressure = state.metrics.get('sleep.pressure') ?? 0,
106
+ isResting = state.metrics.get('state.resting') ?? 0,
107
+ isSleeping = state.metrics.get('state.sleeping') ?? 0,
108
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
109
+ commands: StateCommands = { metrics: [] }
110
+
111
+ const deltaSeconds = delta / 1000
112
+ let newPressure: number
113
+
114
+ if( isSleeping > 0 ){
115
+ // Deep rest — rapid dissipation
116
+ newPressure = Math.max( 0, currentPressure - this._restDissipationRate * deltaSeconds * 2 )
117
+
118
+ // Fully rested event
119
+ if( currentPressure > 5 && newPressure <= 5 )
120
+ events.push({
121
+ type: 'sleep.fully_rested',
122
+ source: this.name,
123
+ payload: { pressure: newPressure },
124
+ })
125
+ }
126
+ else if( isResting > 0 ){
127
+ // Light rest — moderate dissipation
128
+ newPressure = Math.max( 0, currentPressure - this._restDissipationRate * deltaSeconds )
129
+ }
130
+ else {
131
+ // Awake — accumulate pressure
132
+ // Accumulation accelerates as pressure builds (nonlinear fatigue)
133
+ const pressureRatio = currentPressure / this._maxPressure,
134
+ acceleration = 1 + pressureRatio * 1.5,
135
+ accumulation = this._wakeAccumulationRate * acceleration * deltaSeconds
136
+
137
+ newPressure = Math.min( this._maxPressure, currentPressure + accumulation )
138
+
139
+ // Fatigue onset event
140
+ if( currentPressure < this._fatigueThreshold && newPressure >= this._fatigueThreshold )
141
+ events.push({
142
+ type: 'sleep.fatigue_onset',
143
+ source: this.name,
144
+ payload: { pressure: newPressure, threshold: this._fatigueThreshold },
145
+ })
146
+
147
+ // Exhaustion event
148
+ if( currentPressure < this._exhaustionThreshold && newPressure >= this._exhaustionThreshold )
149
+ events.push({
150
+ type: 'sleep.exhaustion',
151
+ source: this.name,
152
+ payload: { pressure: newPressure, threshold: this._exhaustionThreshold },
153
+ })
154
+ }
155
+
156
+ commands.metrics!.push([ 'sleep.pressure', newPressure ])
157
+
158
+ // Drive signal
159
+ const
160
+ intensity = newPressure / this._maxPressure,
161
+ urgency = newPressure >= this._exhaustionThreshold
162
+ ? 1.0
163
+ : newPressure >= this._fatigueThreshold
164
+ ? ( newPressure - this._fatigueThreshold ) / ( this._exhaustionThreshold - this._fatigueThreshold )
165
+ : 0
166
+
167
+ // Mirror drive intensity as a metric so GoalManager._activateFromDrives() can read it
168
+ commands.metrics!.push([ 'drive.sleep', intensity ])
169
+
170
+ events.push({
171
+ type: 'drive.sleep',
172
+ source: this.name,
173
+ payload: {
174
+ name: 'sleep',
175
+ intensity,
176
+ urgency,
177
+ source: this.name,
178
+ } satisfies DriveSignal,
179
+ })
180
+
181
+ // Modulation signals — degrade cognition proportionally to fatigue
182
+ if( newPressure >= this._fatigueThreshold ){
183
+ const fatigueRatio = ( newPressure - this._fatigueThreshold )
184
+ / ( this._maxPressure - this._fatigueThreshold )
185
+
186
+ // Attention degradation
187
+ events.push({
188
+ type: 'modulation.attention_degradation',
189
+ source: this.name,
190
+ payload: {
191
+ target: 'attention-allocator',
192
+ parameter: 'capacity',
193
+ factor: 1 - fatigueRatio * 0.5,
194
+ source: this.name,
195
+ } satisfies ModulationSignal,
196
+ })
197
+
198
+ // Working memory degradation
199
+ events.push({
200
+ type: 'modulation.working_memory_degradation',
201
+ source: this.name,
202
+ payload: {
203
+ target: 'working-memory',
204
+ parameter: 'capacity',
205
+ factor: 1 - fatigueRatio * 0.6,
206
+ source: this.name,
207
+ } satisfies ModulationSignal,
208
+ })
209
+
210
+ // Decision quality degradation (affects LLM temperature or re-evaluation threshold)
211
+ events.push({
212
+ type: 'modulation.decision_quality_degradation',
213
+ source: this.name,
214
+ payload: {
215
+ target: 'decision-engine',
216
+ parameter: 'quality',
217
+ factor: 1 - fatigueRatio * 0.4,
218
+ source: this.name,
219
+ } satisfies ModulationSignal,
220
+ })
221
+ }
222
+
223
+
224
+ // Phase C: publish cognitive event
225
+ const _bus = this._bus
226
+ if( _bus && newPressure > 70 )
227
+ _bus.publish({ type: 'sleep.pressure.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.7, this._model.observe( 'sleep.critical', newPressure ).salience ), payload: { pressure: newPressure } })
228
+ // Phase D + F: rich state-change event — gated by prediction error
229
+ if( _bus ){
230
+ const predErr = this._model.observe( 'sleep.pressure', newPressure )
231
+ if( !predErr.gated )
232
+ _bus.publish({ type: 'sleep.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { pressure: newPressure, intensity } })
233
+ }
234
+
235
+ // Sleep transition events — fire once on edge, not every tick
236
+ const nowSleeping = isSleeping > 0
237
+ if( _bus ){
238
+ if( !this._wasSleeping && nowSleeping )
239
+ _bus.publish({ type: 'sleep.begun', version: 1, sourceEngine: this.name, salience: 0.8, payload: { pressure: newPressure } })
240
+ else if( this._wasSleeping && !nowSleeping )
241
+ _bus.publish({ type: 'sleep.ended', version: 1, sourceEngine: this.name, salience: 0.7, payload: { tick: _tick } })
242
+ }
243
+ this._wasSleeping = nowSleeping
244
+
245
+ return { events: events.length > 0 ? events : undefined, commands }
246
+ }
247
+
248
+ // ── Config hot-reload ────────────────────────────────────
249
+
250
+ private _readConfigFromState( state: ReadonlySimulationState ): void {
251
+ const cfg = state.entities.get('engine-config-sleep')
252
+ if( !cfg ) return
253
+
254
+ const p = cfg.metadata?.params as Record<string, number> | undefined
255
+ if( !p ) return
256
+
257
+ if( p.wakeAccumulationRate != null ) this._wakeAccumulationRate = p.wakeAccumulationRate
258
+ if( p.restDissipationRate != null ) this._restDissipationRate = p.restDissipationRate
259
+ if( p.fatigueThreshold != null ) this._fatigueThreshold = p.fatigueThreshold
260
+ if( p.exhaustionThreshold != null ) this._exhaustionThreshold = p.exhaustionThreshold
261
+ }
262
+ }
@@ -0,0 +1,333 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/social.perception.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * SocialPerception — processes social signals from other agents.
7
+ *
8
+ * Detects and interprets:
9
+ * - Other agents' observable actions
10
+ * - Communication directed at this agent
11
+ * - Social status and relationship cues
12
+ * - Group dynamics and social context
13
+ *
14
+ * Produces social percepts with salience that feed into:
15
+ * - AttachmentEvaluator (to update relationship models)
16
+ * - TheoryOfMind (to update mental models of others)
17
+ * - ThreatEvaluator (social evaluation threat)
18
+ *
19
+ * Part of Shard 0 (Perceptual 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 SocialPerceptionConfig {
36
+ /** Entity types that represent other agents */
37
+ agentTypes?: string[]
38
+ /** Entity types that represent social signals */
39
+ signalTypes?: string[]
40
+ /** Maximum social percepts per tick */
41
+ maxPerceptsPerTick?: number
42
+ bus?: CognitiveBus
43
+ }
44
+
45
+ interface SocialPercept {
46
+ keid: string
47
+ signalType: string
48
+ action: string
49
+ valence: number // -1 (hostile) to +1 (affiliative)
50
+ intensity: number // 0-1
51
+ directedAtSelf: boolean
52
+ salience: number
53
+ }
54
+
55
+ export class SocialPerception implements SimulationEngine, CognitiveEngine {
56
+ readonly name = 'social-perception'
57
+
58
+ private _agentTypes: Set<string>
59
+ private _signalTypes: Set<string>
60
+ private _maxPerceptsPerTick: number
61
+
62
+ // Track previously observed actions for change detection
63
+ private _previousActions = new Map<string, string>() // keid → last action
64
+
65
+ private _bus: CognitiveBus | null = null
66
+
67
+ private readonly _model = new GenerativeModel()
68
+
69
+
70
+ constructor( config: SocialPerceptionConfig = {} ){
71
+ this._bus = config.bus ?? null
72
+ this._agentTypes = new Set( config.agentTypes ?? [
73
+ 'agent', 'user', 'contact', 'persona',
74
+ ])
75
+ this._signalTypes = new Set( config.signalTypes ?? [
76
+ 'message', 'action', 'expression', 'social_signal', 'communication',
77
+ ])
78
+ this._maxPerceptsPerTick = config.maxPerceptsPerTick ?? 20
79
+ }
80
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
81
+
82
+ // ── Engine interface ─────────────────────────────────────
83
+
84
+ subscribes(): string[] { return ['executive.prediction.formed'] }
85
+ publishes(): CognitiveEventSchema[] {
86
+ return [{ type: 'interaction.occurred', version: 1, validate: () => null }]
87
+ }
88
+
89
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
90
+ this._model.observe( e.type, e.salience )
91
+ if( e.type === 'executive.prediction.formed' ){
92
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
93
+ if( p.predictedDomains.includes('social') )
94
+ this._model.setPrecision( 'social.agent_count', 1.0 + p.confidence * 0.5 )
95
+ }
96
+ }
97
+
98
+ snapshot(): Record<string, unknown> { return {} }
99
+
100
+ async react(
101
+ _delta: Duration,
102
+ tick: Tick,
103
+ state: ReadonlySimulationState,
104
+ context: SimulationContext
105
+ ): Promise<EngineResult> {
106
+ const
107
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
108
+ commands: StateCommands = { set: [], delete: [], metrics: [] }
109
+
110
+ const socialPercepts = this._scanSocialSignals( state )
111
+ const capped = socialPercepts.slice( 0, this._maxPerceptsPerTick )
112
+
113
+ // Convert to percept entities
114
+ for( let i = 0; i < capped.length; i++ ){
115
+ const sp = capped[i]!
116
+
117
+ commands.set!.push({
118
+ id: `social-percept-${tick}-${i}`,
119
+ type: 'percept.social',
120
+ metadata: {
121
+ tick,
122
+ keid: sp.keid,
123
+ signalType: sp.signalType,
124
+ action: sp.action,
125
+ valence: sp.valence,
126
+ intensity: sp.intensity,
127
+ directedAtSelf: sp.directedAtSelf,
128
+ salience: sp.salience,
129
+ },
130
+ })
131
+
132
+ // Update relationship metrics for the perceived agent
133
+ this._updateRelationshipMetrics( sp, commands.metrics! )
134
+
135
+ if( sp.salience > 0.5 )
136
+ events.push({
137
+ type: `social.${sp.signalType}`,
138
+ source: this.name,
139
+ payload: sp,
140
+ })
141
+ }
142
+
143
+ // Social presence metrics
144
+ const activeAgents = this._countActiveAgents( state )
145
+ commands.metrics!.push(
146
+ [ 'social.percepts_this_tick', capped.length ],
147
+ [ 'social.active_agents', activeAgents ],
148
+ [ 'social.directed_at_self', capped.filter( sp => sp.directedAtSelf ).length ],
149
+ )
150
+
151
+ // Social evaluation threat — how much social scrutiny exists
152
+ const evaluationThreat = this._computeEvaluationThreat( capped )
153
+ commands.metrics!.push([ 'social.evaluation_threat', evaluationThreat ])
154
+
155
+ // Cleanup
156
+ commands.delete = this._collectStale( state, tick )
157
+
158
+
159
+ // Phase C + F: publish cognitive event — gated by prediction error
160
+ const _bus = this._bus
161
+ if( _bus && activeAgents > 0 ){
162
+ const predErr = this._model.observe( 'social.agent_count', activeAgents )
163
+ if( !predErr.gated )
164
+ _bus.publish({ type: 'social.agents.present', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { activeAgents } })
165
+ }
166
+
167
+ // interaction.occurred — one event per significant percept so subscribers
168
+ // (theory.of.mind, attachment.evaluator, etc.) get rich per-agent context
169
+ if( _bus ){
170
+ for( const sp of capped ){
171
+ if( !sp.directedAtSelf && Math.abs( sp.valence ) < 0.2 ) continue
172
+ _bus.publish({
173
+ type: 'interaction.occurred', version: 1, sourceEngine: this.name,
174
+ salience: sp.salience,
175
+ payload: {
176
+ keid: sp.keid,
177
+ valence: sp.valence,
178
+ intensity: sp.intensity,
179
+ directedAtSelf: sp.directedAtSelf,
180
+ interactionType: sp.signalType,
181
+ },
182
+ })
183
+ }
184
+ }
185
+
186
+ return { events: events.length > 0 ? events : undefined, commands }
187
+ }
188
+
189
+ // ── Internal ─────────────────────────────────────────────
190
+
191
+ private _scanSocialSignals( state: ReadonlySimulationState ): SocialPercept[] {
192
+ const percepts: SocialPercept[] = []
193
+ const selfId = 'agent-self'
194
+
195
+ for( const [ id, entity ] of state.entities ){
196
+ // Only process signal-type entities
197
+ if( !this._signalTypes.has( entity.type ) ) continue
198
+
199
+ const
200
+ sourceKeid = ( entity.metadata?.sourceKeid as string )
201
+ ?? ( entity.metadata?.from as string )
202
+ ?? 'unknown',
203
+ action = ( entity.metadata?.action as string )
204
+ ?? ( entity.metadata?.type as string )
205
+ ?? entity.type,
206
+ directedAtSelf = ( entity.metadata?.recipientId as string ) === selfId
207
+ || ( entity.metadata?.to as string ) === selfId
208
+ || ( entity.metadata?.targetKeid as string ) === selfId
209
+ || entity.metadata?.directedAtSelf === true,
210
+ isNew = this._previousActions.get( sourceKeid ) !== action
211
+
212
+ // Compute valence from entity metadata or defaults
213
+ const valence = typeof entity.metadata?.valence === 'number'
214
+ ? entity.metadata.valence
215
+ : this._defaultValence( action )
216
+
217
+ // Intensity from explicit metadata or salience
218
+ const intensity = typeof entity.metadata?.intensity === 'number'
219
+ ? entity.metadata.intensity
220
+ : typeof entity.metadata?.salience === 'number'
221
+ ? entity.metadata.salience
222
+ : 0.5
223
+
224
+ // Salience: directed at self > new action > repeated action
225
+ const salience = directedAtSelf ? 0.8 + intensity * 0.2
226
+ : isNew ? 0.4 + intensity * 0.3
227
+ : 0.2 + intensity * 0.2
228
+
229
+ percepts.push({
230
+ keid: sourceKeid,
231
+ signalType: entity.type,
232
+ action,
233
+ valence,
234
+ intensity,
235
+ directedAtSelf,
236
+ salience: Math.min( 1, salience ),
237
+ })
238
+
239
+ // Track for change detection
240
+ this._previousActions.set( sourceKeid, action )
241
+ }
242
+
243
+ // Sort by salience
244
+ percepts.sort( ( a, b ) => b.salience - a.salience )
245
+
246
+ return percepts
247
+ }
248
+
249
+ /**
250
+ * Default valence mapping for known action types.
251
+ */
252
+ private _defaultValence( action: string ): number {
253
+ const positive = [ 'praise', 'help', 'cooperate', 'greet', 'smile', 'agree', 'support', 'share' ]
254
+ const negative = [ 'criticize', 'threaten', 'ignore', 'insult', 'attack', 'reject', 'lie', 'betray' ]
255
+
256
+ const lower = action.toLowerCase()
257
+ if( positive.some( p => lower.includes( p ) ) ) return 0.6
258
+ if( negative.some( n => lower.includes( n ) ) ) return -0.6
259
+ return 0
260
+ }
261
+
262
+ /**
263
+ * Update running relationship metrics for a perceived will.
264
+ */
265
+ private _updateRelationshipMetrics(
266
+ percept: SocialPercept,
267
+ metrics: Array<[string, number]>
268
+ ): void {
269
+ const prefix = `relationship.${percept.keid}`
270
+
271
+ // Exponential moving average of interaction valence
272
+ metrics.push([ `${prefix}.valence`, percept.valence ])
273
+
274
+ // Count interactions
275
+ metrics.push([ `${prefix}.interaction_count`, 1 ])
276
+
277
+ // Track directed-at-self ratio
278
+ if( percept.directedAtSelf )
279
+ metrics.push([ `${prefix}.directed_count`, 1 ])
280
+ }
281
+
282
+ private _countActiveAgents( state: ReadonlySimulationState ): number {
283
+ let count = 0
284
+ for( const entity of state.entities.values() ){
285
+ if( this._agentTypes.has( entity.type ) )
286
+ count++
287
+ }
288
+ return count
289
+ }
290
+
291
+ /**
292
+ * Compute social evaluation threat — how much social scrutiny is perceived.
293
+ */
294
+ private _computeEvaluationThreat( percepts: SocialPercept[] ): number {
295
+ if( percepts.length === 0 ) return 0
296
+
297
+ const
298
+ directedPercepts = percepts.filter( p => p.directedAtSelf ),
299
+ negativeDirected = directedPercepts.filter( p => p.valence < 0 )
300
+
301
+ if( directedPercepts.length === 0 ) return 0.1
302
+
303
+ const
304
+ negativeRatio = negativeDirected.length / directedPercepts.length,
305
+ intensityAvg = directedPercepts.reduce( ( s, p ) => s + p.intensity, 0 ) / directedPercepts.length
306
+
307
+ return Math.min( 1, ( negativeRatio * 0.7 + intensityAvg * 0.3 ) * directedPercepts.length / 3 )
308
+ }
309
+
310
+ private _collectStale( state: ReadonlySimulationState, currentTick: Tick ): string[] {
311
+ const stale: string[] = []
312
+ for( const [ id, entity ] of state.entities ){
313
+ // Expire processed percept.social entities after 2 ticks
314
+ if( entity.type === 'percept.social' && typeof entity.metadata?.tick === 'number'){
315
+ if( currentTick - entity.metadata.tick > 2 )
316
+ stale.push( id )
317
+ }
318
+ // Expire injected signal entities (communication, message, etc.) after 2 ticks,
319
+ // BUT only once the executive engine has processed them.
320
+ // communication entities must survive until the executive fires (5-tick cooldown),
321
+ // so we must not delete them before processedByExecutive is set — otherwise
322
+ // messages arriving within 2 ticks of an executive fire are silently lost.
323
+ if( this._signalTypes.has( entity.type ) && entity.type !== 'percept.social'){
324
+ if( entity.type === 'communication' && !entity.metadata?.processedByExecutive ) continue
325
+ const createdAtTick = entity.metadata?.tick as number | undefined
326
+ ?? entity.metadata?.injectedAtTick as number | undefined
327
+ if( typeof createdAtTick === 'number' && currentTick - createdAtTick > 1 )
328
+ stale.push( id )
329
+ }
330
+ }
331
+ return stale
332
+ }
333
+ }