@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,375 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/stress.regulator.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * StressRegulator — tracks cumulative allostatic load.
7
+ *
8
+ * Stress accumulates from:
9
+ * - Unresolved demands (pending goals, unread messages)
10
+ * - Time pressure (deadlines approaching)
11
+ * - Resource scarcity (low energy, high sleep pressure)
12
+ * - Social evaluation (perceived judgment, conflict)
13
+ * - Novelty/uncertainty (unfamiliar situations)
14
+ *
15
+ * Chronic stress degrades cognitive function and biases toward
16
+ * habitual/defensive responses. Acute stress can enhance performance
17
+ * (Yerkes-Dodson curve) up to an optimal point.
18
+ *
19
+ * Part of Shard 0 (Regulatory Layer) — runs every tick, synchronous.
20
+ */
21
+
22
+ import type {
23
+ Duration,
24
+ Tick,
25
+ SimulationContext,
26
+ ReadonlySimulationState,
27
+ StateCommands,
28
+ SimulationEvent,
29
+ DriveSignal,
30
+ ModulationSignal,
31
+ } from '#core/types'
32
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
33
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
34
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
35
+ import { GenerativeModel } from '#cognition/generative.model'
36
+ import { readEffectiveParams } from '#cognition/persona.prior'
37
+
38
+ export interface StressRegulatorConfig {
39
+ /** Maximum allostatic load */
40
+ maxLoad?: number
41
+ /**
42
+ * Fractional clearance rate (per second): the proportion of the *current*
43
+ * load shed each second. Recovery is first-order (exponential), so this also
44
+ * sets the recovery time-constant τ ≈ 1 / rate. Emotional-stability persona
45
+ * development raises it (sheds stress faster); see persona.consolidator #23.
46
+ */
47
+ baseDecayRate?: number
48
+ /** Threshold for optimal stress (peak performance) */
49
+ optimalThreshold?: number
50
+ /** Threshold for distress (cognitive degradation begins) */
51
+ distressThreshold?: number
52
+ /** Threshold for overload (significant impairment) */
53
+ overloadThreshold?: number
54
+ bus?: CognitiveBus
55
+ }
56
+
57
+ interface Stressor {
58
+ type: string
59
+ intensity: number
60
+ source: string
61
+ }
62
+
63
+ export class StressRegulator implements SimulationEngine, CognitiveEngine {
64
+ readonly name = 'stress-regulator'
65
+
66
+ private _maxLoad: number
67
+ private _baseDecayRate: number
68
+ private _optimalThreshold: number
69
+ private _distressThreshold: number
70
+ private _overloadThreshold: number
71
+
72
+ private _energyLevel: number = 100
73
+ private _sleepPressure: number = 0
74
+ private _noveltyScore: number = 0
75
+ private _activeGoalCount: number = 0
76
+ private _metacogConfidence: number = 0.7
77
+
78
+ private _bus: CognitiveBus | null = null
79
+
80
+ private readonly _model = new GenerativeModel( 0.15, 100 )
81
+
82
+
83
+ constructor( config: StressRegulatorConfig = {} ){
84
+ this._bus = config.bus ?? null
85
+ this._maxLoad = config.maxLoad ?? 100
86
+ this._baseDecayRate = config.baseDecayRate ?? 0.05
87
+ this._optimalThreshold = config.optimalThreshold ?? 30
88
+ this._distressThreshold = config.distressThreshold ?? 50
89
+ this._overloadThreshold = config.overloadThreshold ?? 75
90
+ }
91
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
92
+
93
+ // ── Engine interface ─────────────────────────────────────
94
+
95
+
96
+ subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","novelty.state.changed","goal.state.changed","metacognition.state.changed","executive.prediction.formed"] }
97
+ publishes(): CognitiveEventSchema[] { return [] }
98
+
99
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
100
+ this._model.observe( e.type, e.salience )
101
+ switch( e.type ){
102
+ case 'energy.state.changed':
103
+ this._energyLevel = (e.payload as Record<string,number>)['level'] ?? this._energyLevel
104
+ break
105
+ case 'sleep.state.changed':
106
+ this._sleepPressure = (e.payload as Record<string,number>)['pressure'] ?? this._sleepPressure
107
+ break
108
+ case 'novelty.state.changed':
109
+ this._noveltyScore = (e.payload as Record<string,number>)['novelty'] ?? this._noveltyScore
110
+ break
111
+ case 'goal.state.changed':
112
+ this._activeGoalCount = (e.payload as Record<string,number>)['activeCount'] ?? this._activeGoalCount
113
+ break
114
+ case 'metacognition.state.changed':
115
+ this._metacogConfidence = (e.payload as Record<string,number>)['confidence'] ?? this._metacogConfidence
116
+ break
117
+ case 'executive.prediction.formed': {
118
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
119
+ if (p.predictedDomains.includes('stress'))
120
+ this._model.setPrecision('stress.load', 1.0 + p.confidence * 0.5)
121
+ break
122
+ }
123
+ }
124
+ }
125
+
126
+ snapshot(): Record<string, unknown> {
127
+ return {
128
+ energyLevel: this._energyLevel,
129
+ sleepPressure: this._sleepPressure,
130
+ noveltyScore: this._noveltyScore,
131
+ activeGoalCount: this._activeGoalCount,
132
+ metacogConfidence: this._metacogConfidence,
133
+ }
134
+ }
135
+
136
+ async react(
137
+ delta: Duration,
138
+ _tick: Tick,
139
+ state: ReadonlySimulationState,
140
+ context: SimulationContext
141
+ ): Promise<EngineResult> {
142
+ this._readConfigFromState( state )
143
+
144
+ const
145
+ currentLoad = state.metrics.get('stress.load') ?? 0,
146
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
147
+ commands: StateCommands = { metrics: [] }
148
+
149
+ // Compute stressor contributions
150
+ const stressors = this._assessStressors( state, delta )
151
+ const totalStressorIntensity = stressors.reduce( ( s, st ) => s + st.intensity, 0 )
152
+
153
+ // Allostatic load as a leaky integrator with *first-order* (proportional)
154
+ // clearance: dL/dt = Σstressor − k·L. Clearance scales with current load,
155
+ // exactly like physiological recovery — acute spikes shed fast, residual
156
+ // load lingers. This yields a stable, graded equilibrium L* = Σstressor / k
157
+ // for any sustained stressor, so light load settles at a low but non-zero
158
+ // baseline rather than collapsing to 0. A constant absolute leak (the prior
159
+ // model) had no graded equilibrium: it pinned to 0 whenever stressors fell
160
+ // below the leak and ran away to max otherwise.
161
+ //
162
+ // Example: 3 active goals (0.5 each = 1.5/s) at the base k=0.05 settle at
163
+ // L* = 30 — the optimal/eustress band. A steadier Will (higher k, via the
164
+ // emotional-stability prior) settles lower; a less stable one carries more.
165
+ const deltaSeconds = delta / 1000
166
+ const accumulation = totalStressorIntensity * deltaSeconds
167
+ const decay = this._baseDecayRate * currentLoad * deltaSeconds
168
+ const newLoad = Math.max( 0, Math.min( this._maxLoad, currentLoad + accumulation - decay ) )
169
+
170
+ // Recovery event
171
+ if( currentLoad > this._distressThreshold && newLoad <= this._optimalThreshold )
172
+ events.push({
173
+ type: 'stress.recovery',
174
+ source: this.name,
175
+ payload: { previous: currentLoad, current: newLoad },
176
+ })
177
+
178
+ commands.metrics!.push([ 'stress.load', newLoad ])
179
+
180
+ // Identify active stressors for metrics
181
+ for( const stressor of stressors )
182
+ commands.metrics!.push([ `stress.${stressor.type}`, stressor.intensity ])
183
+
184
+ // Determine stress zone
185
+ const zone = newLoad >= this._overloadThreshold ? 'overload'
186
+ : newLoad >= this._distressThreshold ? 'distress'
187
+ : newLoad >= this._optimalThreshold ? 'optimal'
188
+ : 'low'
189
+
190
+ commands.metrics!.push([ 'stress.zone', zone === 'low' ? 0 : zone === 'optimal' ? 1 : zone === 'distress' ? 2 : 3 ])
191
+
192
+ // Zone transition events
193
+ const previousZone = this._getZone( currentLoad )
194
+ if( zone !== previousZone )
195
+ events.push({
196
+ type: `stress.zone_${zone}`,
197
+ source: this.name,
198
+ payload: { load: newLoad, zone, previousZone },
199
+ })
200
+
201
+ // Drive signal — stress itself is a meta-drive (motivates resolution)
202
+ const driveIntensity = newLoad / this._maxLoad
203
+
204
+ // Mirror drive intensity as a metric so GoalManager._activateFromDrives() can read it
205
+ commands.metrics!.push([ 'drive.stress_reduction', newLoad >= this._distressThreshold ? driveIntensity : 0 ])
206
+
207
+ if( newLoad >= this._distressThreshold ){
208
+ events.push({
209
+ type: 'drive.stress_reduction',
210
+ source: this.name,
211
+ payload: {
212
+ name: 'stress_reduction',
213
+ intensity: driveIntensity,
214
+ urgency: newLoad >= this._overloadThreshold ? 1.0 : 0.5,
215
+ source: this.name,
216
+ } satisfies DriveSignal,
217
+ })
218
+ }
219
+
220
+ // Modulation signals — stress affects decision-making
221
+ if( zone === 'overload'){
222
+ // Overload: significant cognitive narrowing
223
+ events.push({
224
+ type: 'modulation.stress_overload',
225
+ source: this.name,
226
+ payload: {
227
+ target: 'decision-engine',
228
+ parameter: 'exploration',
229
+ factor: 0.2, // Strong bias toward habitual/defensive
230
+ source: this.name,
231
+ } satisfies ModulationSignal,
232
+ })
233
+ }
234
+ else if( zone === 'distress'){
235
+ // Distress: moderate impairment, reduced creativity
236
+ events.push({
237
+ type: 'modulation.stress_distress',
238
+ source: this.name,
239
+ payload: {
240
+ target: 'decision-engine',
241
+ parameter: 'creativity',
242
+ factor: 0.6,
243
+ source: this.name,
244
+ } satisfies ModulationSignal,
245
+ })
246
+ }
247
+ else if( zone === 'optimal'){
248
+ // Optimal: enhanced focus, motivation
249
+ events.push({
250
+ type: 'modulation.stress_optimal',
251
+ source: this.name,
252
+ payload: {
253
+ target: 'attention-allocator',
254
+ parameter: 'capacity',
255
+ factor: 1.1, // Slight boost
256
+ source: this.name,
257
+ } satisfies ModulationSignal,
258
+ })
259
+ }
260
+
261
+
262
+ // Phase C: publish cognitive event
263
+ const _bus = this._bus
264
+ if( _bus && ( zone === 'distress' || zone === 'overload' ) )
265
+ _bus.publish({ type: 'stress.zone.transition', version: 1, sourceEngine: this.name, salience: Math.min(1, newLoad / 100), payload: { zone, load: newLoad } })
266
+ // Phase D + F: rich state-change event — gated by prediction error
267
+ if( _bus ){
268
+ const zoneCode = zone === 'low' ? 0 : zone === 'optimal' ? 1 : zone === 'distress' ? 2 : 3
269
+ const predErr = this._model.observe( 'stress.load', newLoad )
270
+ if( !predErr.gated || zone !== previousZone ){
271
+ _bus.publish({ type: 'stress.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { load: newLoad, zoneCode, deadlineUrgency: state.metrics.get('deadline.urgency') ?? 0, cognitiveLoad: state.metrics.get('cognitive.load') ?? state.metrics.get('attention.usage') ?? 0 } })
272
+ }
273
+ }
274
+ return { events: events.length > 0 ? events : undefined, commands }
275
+ }
276
+
277
+ // ── Config hot-reload ────────────────────────────────────
278
+
279
+ private _readConfigFromState( state: ReadonlySimulationState ): void {
280
+ // Effective config = base engine-config-stress ⊕ persona-prior. Channel A: a steadier
281
+ // (emotionally-stable) Will develops a higher baseDecayRate and so sheds stress faster.
282
+ const p = readEffectiveParams( state, 'engine-config-stress' )
283
+ if( p.baseDecayRate != null ) this._baseDecayRate = p.baseDecayRate
284
+ if( p.optimalThreshold != null ) this._optimalThreshold = p.optimalThreshold
285
+ if( p.distressThreshold != null ) this._distressThreshold = p.distressThreshold
286
+ if( p.overloadThreshold != null ) this._overloadThreshold = p.overloadThreshold
287
+ }
288
+
289
+ // ── Internal ─────────────────────────────────────────────
290
+
291
+ /**
292
+ * Assess active stressors from the current state.
293
+ */
294
+ private _assessStressors( state: ReadonlySimulationState, delta: Duration ): Stressor[] {
295
+ const stressors: Stressor[] = []
296
+
297
+ // Demand pressure: active goals requiring action. ~0.5/goal so a handful of
298
+ // concurrent goals lands in the eustress band (3 goals ⇒ ≈optimal at base
299
+ // k); capped at 2 so goals alone plateau around distress and it takes
300
+ // compounding stressors (fatigue, low energy, deadlines) to reach overload.
301
+ const activeGoals = this._activeGoalCount
302
+ if( activeGoals > 0 )
303
+ stressors.push({
304
+ type: 'demand',
305
+ intensity: Math.min( activeGoals * 0.5, 2 ),
306
+ source: 'goals',
307
+ })
308
+
309
+ // Time pressure: deadlines approaching
310
+ const
311
+ nearestDeadline = state.metrics.get('deadline.nearest'),
312
+ deadlinePressure = nearestDeadline !== undefined && nearestDeadline > 0
313
+ ? Math.min( 30, 300 / Math.max( nearestDeadline, 1 ) )
314
+ : 0
315
+
316
+ if( deadlinePressure > 0 )
317
+ stressors.push({
318
+ type: 'time_pressure',
319
+ intensity: deadlinePressure,
320
+ source: 'deadlines',
321
+ })
322
+
323
+ // Resource scarcity: low energy
324
+ const energyLevel = this._energyLevel,
325
+ energyMax = 100,
326
+ energyRatio = energyLevel / energyMax
327
+
328
+ if( energyRatio < 0.3 )
329
+ stressors.push({
330
+ type: 'resource_scarcity',
331
+ intensity: Math.min( 3, ( 0.3 - energyRatio ) * 15 ),
332
+ source: 'energy',
333
+ })
334
+
335
+ // Sleep pressure as stressor
336
+ const sleepPressure = this._sleepPressure
337
+ if( sleepPressure > 40 )
338
+ stressors.push({
339
+ type: 'fatigue',
340
+ intensity: Math.min( 3, ( sleepPressure / 100 ) * 5 ),
341
+ source: 'sleep',
342
+ })
343
+
344
+ // Social evaluation: perceived judgment
345
+ const socialThreat = state.metrics.get('social.evaluation_threat') ?? 0
346
+ if( socialThreat > 0 )
347
+ stressors.push({
348
+ type: 'social_evaluation',
349
+ intensity: Math.min( 2, socialThreat * 5 ),
350
+ source: 'social',
351
+ })
352
+
353
+ // Uncertainty: novelty + low predictability
354
+ const
355
+ novelty = this._noveltyScore,
356
+ confidence = this._metacogConfidence,
357
+ uncertainty = Math.min( 2, novelty * ( 1 - confidence ) * 5 )
358
+
359
+ if( uncertainty > 0 )
360
+ stressors.push({
361
+ type: 'uncertainty',
362
+ intensity: uncertainty,
363
+ source: 'perception',
364
+ })
365
+
366
+ return stressors
367
+ }
368
+
369
+ private _getZone( load: number ): string {
370
+ return load >= this._overloadThreshold ? 'overload'
371
+ : load >= this._distressThreshold ? 'distress'
372
+ : load >= this._optimalThreshold ? 'optimal'
373
+ : 'low'
374
+ }
375
+ }
@@ -0,0 +1,239 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/task.switcher.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * TaskSwitcher — manages attention shifts between competing goals.
7
+ *
8
+ * When multiple goals compete for attention, the TaskSwitcher:
9
+ * 1. Compares active goal priorities
10
+ * 2. Applies switching costs (attention residue from previous focus)
11
+ * 3. Decides whether to maintain current focus or switch
12
+ * 4. Signals the AttentionAllocator to reallocate
13
+ *
14
+ * Switching is costly — frequent switching degrades performance.
15
+ * The TaskSwitcher balances exploitation (stay on current goal) vs.
16
+ * exploration (switch to potentially higher-value goal).
17
+ *
18
+ * Part of Shard 3 (Executive Layer) — runs every tick, synchronous.
19
+ */
20
+
21
+ import type {
22
+ Duration,
23
+ Tick,
24
+ SimulationContext,
25
+ ReadonlySimulationState,
26
+ StateCommands,
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
+ import { readEffectiveParams } from '#cognition/persona.prior'
34
+
35
+ export interface TaskSwitcherConfig {
36
+ /** Base switching cost (0-1, fraction of attention lost on switch) */
37
+ baseSwitchCost?: number
38
+ /** How much priority advantage a new goal needs to justify switching */
39
+ switchThreshold?: number
40
+ /** Minimum ticks on a goal before switching is considered */
41
+ minFocusTicks?: number
42
+ bus?: CognitiveBus
43
+ }
44
+
45
+ interface CurrentFocus {
46
+ goalId: string | null
47
+ focusTicks: number
48
+ startedAt: Tick
49
+ }
50
+
51
+ export class TaskSwitcher implements SimulationEngine, CognitiveEngine {
52
+ readonly name = 'task-switcher'
53
+
54
+ private _baseSwitchCost: number
55
+ private _switchThreshold: number
56
+ private _minFocusTicks: number
57
+
58
+ private _currentFocus: CurrentFocus = {
59
+ goalId: null,
60
+ focusTicks: 0,
61
+ startedAt: 0,
62
+ }
63
+
64
+ private _totalSwitches = 0
65
+
66
+ private _bus: CognitiveBus | null = null
67
+
68
+ private readonly _model = new GenerativeModel()
69
+
70
+
71
+ constructor( config: TaskSwitcherConfig = {} ){
72
+ this._bus = config.bus ?? null
73
+ this._baseSwitchCost = config.baseSwitchCost ?? 0.3
74
+ this._switchThreshold = config.switchThreshold ?? 0.2
75
+ this._minFocusTicks = config.minFocusTicks ?? 3
76
+ }
77
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
78
+
79
+ // ── Engine interface ─────────────────────────────────────
80
+
81
+ private _readConfigFromState( state: ReadonlySimulationState ): void {
82
+ // Effective config = base engine-config-task-switcher ⊕ persona-prior. Channel A: a
83
+ // conscientious Will develops a higher baseSwitchCost and so is less distractible.
84
+ const p = readEffectiveParams( state, 'engine-config-task-switcher' )
85
+ if( p.baseSwitchCost != null ) this._baseSwitchCost = p.baseSwitchCost
86
+ if( p.switchThreshold != null ) this._switchThreshold = p.switchThreshold
87
+ if( p.minFocusTicks != null ) this._minFocusTicks = p.minFocusTicks
88
+ }
89
+
90
+
91
+ subscribes(): string[] { return ['executive.prediction.formed'] }
92
+ publishes(): CognitiveEventSchema[] { return [] }
93
+
94
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
95
+ this._model.observe( e.type, e.salience )
96
+ if( e.type === 'executive.prediction.formed' ){
97
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
98
+ if( p.predictedDomains.includes('executive') )
99
+ this._model.setPrecision( 'task.focus_ticks', 1.0 + p.confidence * 0.5 )
100
+ }
101
+ }
102
+
103
+ snapshot(): Record<string, unknown> { return {} }
104
+
105
+ async react(
106
+ _delta: Duration,
107
+ tick: Tick,
108
+ state: ReadonlySimulationState,
109
+ context: SimulationContext
110
+ ): Promise<EngineResult> {
111
+ this._readConfigFromState( state )
112
+
113
+ const
114
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
115
+ commands: StateCommands = { metrics: [] }
116
+
117
+ // 1. Get active goals sorted by priority
118
+ const activeGoals = this._getActiveGoals( state )
119
+
120
+ // 2. Increment focus counter
121
+ this._currentFocus.focusTicks++
122
+
123
+ // 3. Evaluate whether to switch
124
+ let switched = false
125
+ let switchReason = ''
126
+
127
+ if( activeGoals.length > 0 ){
128
+ const topGoal = activeGoals[0]!
129
+
130
+ if( this._currentFocus.goalId === null ){
131
+ // First focus — adopt the top goal
132
+ this._currentFocus = {
133
+ goalId: topGoal.id,
134
+ focusTicks: 0,
135
+ startedAt: tick,
136
+ }
137
+ switched = true
138
+ switchReason = 'initial_focus'
139
+ }
140
+ else if( topGoal.id !== this._currentFocus.goalId ){
141
+ // Potential switch — evaluate
142
+ const currentGoal = activeGoals.find( g => g.id === this._currentFocus.goalId )
143
+ const currentPriority = currentGoal?.priority ?? 0
144
+ const switchAdvantage = topGoal.priority - currentPriority
145
+
146
+ // Account for switching cost
147
+ const switchCost = this._baseSwitchCost * ( 1 + this._currentFocus.focusTicks * 0.01 )
148
+ const netBenefit = switchAdvantage - switchCost
149
+
150
+ if( netBenefit > this._switchThreshold
151
+ && this._currentFocus.focusTicks >= this._minFocusTicks ){
152
+ // Switch
153
+ this._currentFocus = {
154
+ goalId: topGoal.id,
155
+ focusTicks: 0,
156
+ startedAt: tick,
157
+ }
158
+ this._totalSwitches++
159
+ switched = true
160
+ switchReason = `switched_from_${currentGoal?.description ?? 'unknown'}_to_${topGoal.description}`
161
+ }
162
+ }
163
+ }
164
+ else if( this._currentFocus.goalId !== null ){
165
+ // No active goals — release focus
166
+ this._currentFocus = { goalId: null, focusTicks: 0, startedAt: 0 }
167
+ switched = true
168
+ switchReason = 'no_active_goals'
169
+ }
170
+
171
+ // 4. Update metrics
172
+ commands.metrics!.push(
173
+ [ 'task_switch.current_focus_ticks', this._currentFocus.focusTicks ],
174
+ [ 'task_switch.total_switches', this._totalSwitches ],
175
+ [ 'task_switch.switch_cost', this._baseSwitchCost ],
176
+ )
177
+
178
+ // 5. Persist current focus
179
+ if( this._currentFocus.goalId ){
180
+ commands.set = [{
181
+ id: 'task-switch-focus',
182
+ type: 'task.focus',
183
+ createdAt: this._currentFocus.startedAt,
184
+ metadata: {
185
+ goalId: this._currentFocus.goalId,
186
+ focusTicks: this._currentFocus.focusTicks,
187
+ startedAt: this._currentFocus.startedAt,
188
+ },
189
+ }]
190
+ }
191
+
192
+ if( switched )
193
+ events.push({
194
+ type: 'task_switch.executed',
195
+ source: this.name,
196
+ payload: {
197
+ newGoalId: this._currentFocus.goalId,
198
+ reason: switchReason,
199
+ totalSwitches: this._totalSwitches,
200
+ },
201
+ })
202
+
203
+
204
+ // Phase C + F: publish cognitive event — gated by prediction error
205
+ const _bus = this._bus
206
+ if( _bus ){
207
+ const predErr = this._model.observe( 'task.focus_ticks', this._currentFocus.focusTicks )
208
+ if( !predErr.gated )
209
+ _bus.publish({ type: 'task.focus.changed', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { focusTicks: this._currentFocus.focusTicks } })
210
+ }
211
+ return { events: events.length > 0 ? events : undefined, commands }
212
+ }
213
+
214
+ // ── Internal ─────────────────────────────────────────────
215
+
216
+ private _getActiveGoals( state: ReadonlySimulationState ): Array<{ id: string; priority: number; description: string }> {
217
+ const goals: Array<{ id: string; priority: number; description: string }> = []
218
+
219
+ for( const entity of state.entities.values() ){
220
+ if( entity.type === 'goal' && entity.metadata?.status === 'active'){
221
+ goals.push({
222
+ id: entity.id,
223
+ priority: ( entity.metadata.priority as number ) ?? 0,
224
+ description: ( entity.metadata.description as string ) ?? entity.id,
225
+ })
226
+ }
227
+ }
228
+
229
+ goals.sort( ( a, b ) => b.priority - a.priority )
230
+ return goals
231
+ }
232
+
233
+ /**
234
+ * Get the current focus goal ID.
235
+ */
236
+ getCurrentFocus(): string | null {
237
+ return this._currentFocus.goalId
238
+ }
239
+ }