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