@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,432 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/attachment.evaluator.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AttachmentEvaluator — models relationship bonds with other agents.
|
|
7
|
+
*
|
|
8
|
+
* Evaluates:
|
|
9
|
+
* - Interaction frequency and recency
|
|
10
|
+
* - Positive vs. negative interaction ratio
|
|
11
|
+
* - Dependency (how much the agent relies on this other)
|
|
12
|
+
* - Trust history (reliability over time)
|
|
13
|
+
* - Shared experience depth
|
|
14
|
+
*
|
|
15
|
+
* Produces: love, trust, belonging, loneliness
|
|
16
|
+
*
|
|
17
|
+
* Love = strong positive bond with specific other
|
|
18
|
+
* Trust = confidence in another's reliability and benevolence
|
|
19
|
+
* Belonging = sense of connection to a social group
|
|
20
|
+
* Loneliness = absence of meaningful attachment
|
|
21
|
+
*
|
|
22
|
+
* Attachment builds gradually (repeated positive interactions) and
|
|
23
|
+
* decays slowly (bonds persist through absence, but fade over time).
|
|
24
|
+
*
|
|
25
|
+
* Part of Shard 1 (Affective Layer) — runs every tick, synchronous.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
Duration,
|
|
30
|
+
Tick,
|
|
31
|
+
SimulationContext,
|
|
32
|
+
ReadonlySimulationState,
|
|
33
|
+
StateCommands,
|
|
34
|
+
SimulationEvent,
|
|
35
|
+
} from '#core/types'
|
|
36
|
+
import type { CognitiveEngine, SimulationEngine, EngineResult } from '#cognition/types'
|
|
37
|
+
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
38
|
+
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
39
|
+
import { GenerativeModel } from '#cognition/generative.model'
|
|
40
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
41
|
+
|
|
42
|
+
export interface AttachmentEvaluatorConfig {
|
|
43
|
+
/** How quickly attachment builds from positive interactions */
|
|
44
|
+
attachmentGrowthRate?: number
|
|
45
|
+
/** How slowly attachment decays during absence */
|
|
46
|
+
attachmentDecayRate?: number
|
|
47
|
+
/** Threshold for loneliness to become significant */
|
|
48
|
+
lonelinessThreshold?: number
|
|
49
|
+
/** Minimum interactions to consider a bond meaningful */
|
|
50
|
+
minInteractionsForBond?: number
|
|
51
|
+
/**
|
|
52
|
+
* Baseline belonging from self-awareness (0–1).
|
|
53
|
+
* Prevents loneliness from maxing out at boot with no social context.
|
|
54
|
+
* 0.35 ≈ "I know who I am" — connected to self but still meaningfully alone.
|
|
55
|
+
*/
|
|
56
|
+
selfBelonging?: number
|
|
57
|
+
bus?: CognitiveBus
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface BondModel {
|
|
61
|
+
keid: string
|
|
62
|
+
attachmentStrength: number // 0-1: overall bond strength
|
|
63
|
+
trustLevel: number // 0-1: reliability assessment
|
|
64
|
+
positiveRatio: number // 0-1: proportion of positive interactions
|
|
65
|
+
interactionCount: number
|
|
66
|
+
lastInteractionTick: number
|
|
67
|
+
sharedExperiences: number
|
|
68
|
+
dependency: number // 0-1: how much agent relies on this other
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class AttachmentEvaluator implements SimulationEngine, CognitiveEngine {
|
|
72
|
+
readonly name = 'attachment-evaluator'
|
|
73
|
+
|
|
74
|
+
private _growthRate: number
|
|
75
|
+
private _decayRate: number
|
|
76
|
+
private _lonelinessThreshold: number
|
|
77
|
+
private _minInteractionsForBond: number
|
|
78
|
+
private _selfBelonging: number
|
|
79
|
+
|
|
80
|
+
// Persistent bond models across ticks
|
|
81
|
+
private _bonds = new Map<string, BondModel>()
|
|
82
|
+
// True after bonds have been rehydrated from snapshot state on first tick
|
|
83
|
+
private _restored = false
|
|
84
|
+
|
|
85
|
+
// Inputs from cognitive events
|
|
86
|
+
private _pendingInteractions: Array<{
|
|
87
|
+
keid: string; valence: number; intensity: number
|
|
88
|
+
directedAtSelf: boolean; sharedExperience: boolean
|
|
89
|
+
}> = []
|
|
90
|
+
private _cachedActiveAgents: number = 0
|
|
91
|
+
private _cachedBelonging: number = 0
|
|
92
|
+
|
|
93
|
+
private _bus: CognitiveBus | null = null
|
|
94
|
+
|
|
95
|
+
private readonly _model = new GenerativeModel()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
constructor( config: AttachmentEvaluatorConfig = {} ){
|
|
99
|
+
this._bus = config.bus ?? null
|
|
100
|
+
this._growthRate = config.attachmentGrowthRate ?? 0.05
|
|
101
|
+
this._decayRate = config.attachmentDecayRate ?? 0.002
|
|
102
|
+
this._lonelinessThreshold = config.lonelinessThreshold ?? 0.4
|
|
103
|
+
this._minInteractionsForBond = config.minInteractionsForBond ?? 3
|
|
104
|
+
this._selfBelonging = config.selfBelonging ?? 0.35
|
|
105
|
+
}
|
|
106
|
+
attachBus( bus: CognitiveBus ): void { this._bus = bus }
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Attachment strength (0–1) toward a specific agent, or 0 if no bond exists.
|
|
110
|
+
* Read-only accessor used by the AuditionEngine to weight conversational
|
|
111
|
+
* salience by relationship closeness.
|
|
112
|
+
*/
|
|
113
|
+
getAttachmentScore( keid: string ): number {
|
|
114
|
+
return this._bonds.get( keid )?.attachmentStrength ?? 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Engine interface ─────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
subscribes(): string[] {
|
|
120
|
+
return [
|
|
121
|
+
'executive.prediction.formed',
|
|
122
|
+
'interaction.occurred',
|
|
123
|
+
'social.agents.present',
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
publishes(): CognitiveEventSchema[] { return [] }
|
|
128
|
+
|
|
129
|
+
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
130
|
+
this._model.observe( e.type, e.salience )
|
|
131
|
+
if( e.type === 'executive.prediction.formed' ){
|
|
132
|
+
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
133
|
+
if( p.predictedDomains.includes('social') )
|
|
134
|
+
this._model.setPrecision( 'emotion.love', 1.0 + p.confidence * 0.5 )
|
|
135
|
+
}
|
|
136
|
+
if( e.type === 'interaction.occurred' ){
|
|
137
|
+
const p = e.payload as {
|
|
138
|
+
keid: string; valence: number; intensity: number
|
|
139
|
+
directedAtSelf: boolean; interactionType: string
|
|
140
|
+
}
|
|
141
|
+
this._pendingInteractions.push({
|
|
142
|
+
keid: p.keid,
|
|
143
|
+
valence: p.valence,
|
|
144
|
+
intensity: p.intensity,
|
|
145
|
+
directedAtSelf: p.directedAtSelf,
|
|
146
|
+
sharedExperience: false,
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
if( e.type === 'social.agents.present' ){
|
|
150
|
+
const p = e.payload as { activeAgents: number }
|
|
151
|
+
this._cachedActiveAgents = p.activeAgents
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
snapshot(): Record<string, unknown> { return {} }
|
|
156
|
+
|
|
157
|
+
async react(
|
|
158
|
+
delta: Duration,
|
|
159
|
+
tick: Tick,
|
|
160
|
+
state: ReadonlySimulationState,
|
|
161
|
+
_context: SimulationContext
|
|
162
|
+
): Promise<EngineResult> {
|
|
163
|
+
const
|
|
164
|
+
events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
|
|
165
|
+
commands: StateCommands = { metrics: [] }
|
|
166
|
+
|
|
167
|
+
// Channel A (agreeableness → attachment): how fast bonds form is refreshed each tick as
|
|
168
|
+
// base ⊕ persona-prior. An agreeable Will develops a higher growth rate and bonds more
|
|
169
|
+
// readily. (Seed existed but was ignored.)
|
|
170
|
+
this._growthRate = readEffectiveParams( state, 'engine-config-attachment' ).attachmentGrowthRate ?? this._growthRate
|
|
171
|
+
|
|
172
|
+
// On the very first tick after construction (including snapshot restores),
|
|
173
|
+
// rehydrate _bonds from attachment.bond entities written by _persistBonds().
|
|
174
|
+
// Without this, a restored Will starts with an empty bond Map and immediately
|
|
175
|
+
// overwrites all saved attachment data with zeros on the first persist cycle.
|
|
176
|
+
if( !this._restored ){
|
|
177
|
+
this._restoreFromState( state )
|
|
178
|
+
this._restored = true
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 1. Drain buffered interactions and update bond models
|
|
182
|
+
const interactions = this._pendingInteractions.splice( 0 )
|
|
183
|
+
this._processSocialSignals( interactions, tick )
|
|
184
|
+
|
|
185
|
+
// 2. Decay bonds for absent agents
|
|
186
|
+
this._decayBonds( delta, tick )
|
|
187
|
+
|
|
188
|
+
// 3. Compute attachment emotions from bond models
|
|
189
|
+
const positiveCount = interactions.filter( i => i.valence > 0.3 ).length
|
|
190
|
+
const
|
|
191
|
+
love = this._computeLove(),
|
|
192
|
+
trust = this._computeTrust(),
|
|
193
|
+
belonging = this._computeBelonging( positiveCount ),
|
|
194
|
+
loneliness = this._computeLoneliness( belonging )
|
|
195
|
+
this._cachedBelonging = belonging
|
|
196
|
+
|
|
197
|
+
commands.metrics!.push(
|
|
198
|
+
[ 'emotion.love', love ],
|
|
199
|
+
[ 'emotion.trust', trust ],
|
|
200
|
+
[ 'emotion.belonging', belonging ],
|
|
201
|
+
[ 'emotion.loneliness', loneliness ],
|
|
202
|
+
[ 'attachment.bond_count', this._bonds.size ],
|
|
203
|
+
[ 'attachment.strongest_bond', this._strongestBondStrength() ],
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
// Persist bond models as entities for other engines to read
|
|
207
|
+
this._persistBonds( commands, tick )
|
|
208
|
+
|
|
209
|
+
// Significant bond events
|
|
210
|
+
const strongestBond = this._strongestBond()
|
|
211
|
+
if( strongestBond && strongestBond.attachmentStrength > 0.7 )
|
|
212
|
+
events.push({
|
|
213
|
+
type: 'attachment.strong_bond',
|
|
214
|
+
source: this.name,
|
|
215
|
+
payload: {
|
|
216
|
+
keid: strongestBond.keid,
|
|
217
|
+
strength: strongestBond.attachmentStrength,
|
|
218
|
+
trust: strongestBond.trustLevel,
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
if( loneliness > this._lonelinessThreshold )
|
|
223
|
+
events.push({
|
|
224
|
+
type: 'emotion.loneliness.significant',
|
|
225
|
+
source: this.name,
|
|
226
|
+
payload: { loneliness, belonging, bondCount: this._bonds.size },
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
// Phase C: publish cognitive event
|
|
231
|
+
const _bus = this._bus
|
|
232
|
+
if( _bus && love > 0.5 ){
|
|
233
|
+
const predErr = this._model.observe( 'emotion.love', love )
|
|
234
|
+
if( !predErr.gated )
|
|
235
|
+
_bus.publish({ type: 'emotion.love.significant', version: 1, sourceEngine: this.name, salience: Math.min(1, love), payload: { love } })
|
|
236
|
+
}
|
|
237
|
+
return { events: events.length > 0 ? events : undefined, commands }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ── Bond model management ────────────────────────────────
|
|
241
|
+
|
|
242
|
+
private _processSocialSignals(
|
|
243
|
+
interactions: Array<{ keid: string; valence: number; intensity: number; directedAtSelf: boolean; sharedExperience: boolean }>,
|
|
244
|
+
tick: Tick
|
|
245
|
+
): void {
|
|
246
|
+
for( const interaction of interactions ){
|
|
247
|
+
const
|
|
248
|
+
keid = interaction.keid,
|
|
249
|
+
valence = interaction.valence,
|
|
250
|
+
directedAtSelf = interaction.directedAtSelf,
|
|
251
|
+
isSharedExp = interaction.sharedExperience
|
|
252
|
+
|
|
253
|
+
if( !keid || keid === 'agent-self') continue
|
|
254
|
+
|
|
255
|
+
let bond = this._bonds.get( keid )
|
|
256
|
+
|
|
257
|
+
if( !bond ){
|
|
258
|
+
bond = {
|
|
259
|
+
keid,
|
|
260
|
+
attachmentStrength: 0,
|
|
261
|
+
trustLevel: 0.5, // Neutral starting trust
|
|
262
|
+
positiveRatio: 0.5,
|
|
263
|
+
interactionCount: 0,
|
|
264
|
+
lastInteractionTick: tick,
|
|
265
|
+
sharedExperiences: 0,
|
|
266
|
+
dependency: 0,
|
|
267
|
+
}
|
|
268
|
+
this._bonds.set( keid, bond )
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Update bond metrics
|
|
272
|
+
bond.interactionCount++
|
|
273
|
+
bond.lastInteractionTick = tick
|
|
274
|
+
|
|
275
|
+
// Positive ratio — exponential moving average
|
|
276
|
+
const isPositive = valence > 0
|
|
277
|
+
bond.positiveRatio += this._growthRate * ( ( isPositive ? 1 : 0 ) - bond.positiveRatio )
|
|
278
|
+
|
|
279
|
+
// Attachment strength grows with positive interactions
|
|
280
|
+
if( directedAtSelf ){
|
|
281
|
+
const valenceContribution = valence * 0.1
|
|
282
|
+
bond.attachmentStrength = Math.min( 1,
|
|
283
|
+
bond.attachmentStrength + valenceContribution * this._growthRate
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Trust builds from consistent positive interactions over time
|
|
288
|
+
if( bond.interactionCount >= this._minInteractionsForBond ){
|
|
289
|
+
const reliabilitySignal = isPositive ? 0.1 : -0.15 // Betrayal hurts trust more than reliability builds it
|
|
290
|
+
bond.trustLevel = Math.min( 1, Math.max( 0,
|
|
291
|
+
bond.trustLevel + reliabilitySignal * this._growthRate
|
|
292
|
+
))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Shared experiences deepen bonds
|
|
296
|
+
if( isSharedExp ){
|
|
297
|
+
bond.sharedExperiences++
|
|
298
|
+
bond.attachmentStrength = Math.min( 1,
|
|
299
|
+
bond.attachmentStrength + 0.03 * this._growthRate
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Dependency increases with interaction frequency
|
|
304
|
+
bond.dependency = Math.min( 1, bond.interactionCount / 100 )
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private _decayBonds( delta: Duration, currentTick: Tick ): void {
|
|
309
|
+
const deltaSeconds = delta / 1000
|
|
310
|
+
|
|
311
|
+
for( const [ id, bond ] of this._bonds ){
|
|
312
|
+
const ticksSinceLastInteraction = currentTick - bond.lastInteractionTick
|
|
313
|
+
|
|
314
|
+
// Attachment decays slowly during absence
|
|
315
|
+
if( ticksSinceLastInteraction > 10 ){
|
|
316
|
+
const decayFactor = this._decayRate * deltaSeconds * ( ticksSinceLastInteraction / 100 )
|
|
317
|
+
bond.attachmentStrength = Math.max( 0, bond.attachmentStrength - decayFactor )
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Very old bonds with no interactions can be pruned
|
|
321
|
+
if( ticksSinceLastInteraction > 1000 && bond.attachmentStrength < 0.05 )
|
|
322
|
+
this._bonds.delete( id )
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ── Emotion computation ──────────────────────────────────
|
|
327
|
+
|
|
328
|
+
private _computeLove(): number {
|
|
329
|
+
// Love = strongest attachment bond, thresholded
|
|
330
|
+
const strongest = this._strongestBondStrength()
|
|
331
|
+
return strongest > 0.4 ? strongest : 0
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private _computeTrust(): number {
|
|
335
|
+
// Trust = average trust level across bonds, weighted by attachment
|
|
336
|
+
if( this._bonds.size === 0 ) return 0.5 // Neutral baseline
|
|
337
|
+
|
|
338
|
+
let weightedTrust = 0
|
|
339
|
+
let totalWeight = 0
|
|
340
|
+
|
|
341
|
+
for( const bond of this._bonds.values() ){
|
|
342
|
+
const weight = bond.attachmentStrength + 0.1
|
|
343
|
+
weightedTrust += bond.trustLevel * weight
|
|
344
|
+
totalWeight += weight
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return totalWeight > 0 ? weightedTrust / totalWeight : 0.5
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private _computeBelonging( positiveSignalCount: number ): number {
|
|
351
|
+
const
|
|
352
|
+
bondCount = this._bonds.size,
|
|
353
|
+
meanStrength = bondCount > 0
|
|
354
|
+
? Array.from( this._bonds.values() ).reduce( ( s, b ) => s + b.attachmentStrength, 0 ) / bondCount
|
|
355
|
+
: 0,
|
|
356
|
+
socialPresence = this._cachedActiveAgents,
|
|
357
|
+
positiveSignals = Math.min( 1, positiveSignalCount / 5 )
|
|
358
|
+
|
|
359
|
+
const computed = Math.min( 1,
|
|
360
|
+
Math.min( bondCount / 3, 1 ) * 0.4
|
|
361
|
+
+ meanStrength * 0.3
|
|
362
|
+
+ Math.min( socialPresence / 5, 1 ) * 0.15
|
|
363
|
+
+ positiveSignals * 0.15
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
// Self-awareness provides a baseline — the Will is never entirely without
|
|
367
|
+
// connection to itself. Social bonds can only add to this floor, not replace it.
|
|
368
|
+
return Math.max( this._selfBelonging, computed )
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private _computeLoneliness( belonging: number ): number {
|
|
372
|
+
// Loneliness spikes when belonging is very low
|
|
373
|
+
return belonging > 0.6 ? 0
|
|
374
|
+
: belonging > 0.3 ? ( 0.6 - belonging ) * 1.5
|
|
375
|
+
: 1 - belonging * 0.5
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ── Helpers ──────────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
private _strongestBond(): BondModel | null {
|
|
381
|
+
let strongest: BondModel | null = null
|
|
382
|
+
for( const bond of this._bonds.values() ){
|
|
383
|
+
if( !strongest || bond.attachmentStrength > strongest.attachmentStrength )
|
|
384
|
+
strongest = bond
|
|
385
|
+
}
|
|
386
|
+
return strongest
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private _strongestBondStrength(): number {
|
|
390
|
+
return this._strongestBond()?.attachmentStrength ?? 0
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private _restoreFromState( state: ReadonlySimulationState ): void {
|
|
394
|
+
for( const entity of state.entities.values() ){
|
|
395
|
+
if( entity.type !== 'attachment.bond') continue
|
|
396
|
+
const m = entity.metadata
|
|
397
|
+
if( !m?.keid ) continue
|
|
398
|
+
|
|
399
|
+
this._bonds.set( m.keid as string, {
|
|
400
|
+
keid: m.keid as string,
|
|
401
|
+
attachmentStrength: m.strength as number ?? 0,
|
|
402
|
+
trustLevel: m.trust as number ?? 0.5,
|
|
403
|
+
positiveRatio: m.positiveRatio as number ?? 0.5,
|
|
404
|
+
interactionCount: m.interactionCount as number ?? 0,
|
|
405
|
+
lastInteractionTick: m.lastInteractionTick as number ?? 0,
|
|
406
|
+
sharedExperiences: m.sharedExperiences as number ?? 0,
|
|
407
|
+
dependency: m.dependency as number ?? 0,
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private _persistBonds( commands: StateCommands, tick: Tick ): void {
|
|
413
|
+
for( const bond of this._bonds.values() ){
|
|
414
|
+
commands.set ??= []
|
|
415
|
+
commands.set.push({
|
|
416
|
+
id: `bond-${bond.keid}`,
|
|
417
|
+
type: 'attachment.bond',
|
|
418
|
+
metadata: {
|
|
419
|
+
keid: bond.keid,
|
|
420
|
+
strength: bond.attachmentStrength,
|
|
421
|
+
trust: bond.trustLevel,
|
|
422
|
+
positiveRatio: bond.positiveRatio,
|
|
423
|
+
interactionCount: bond.interactionCount,
|
|
424
|
+
lastInteractionTick: bond.lastInteractionTick,
|
|
425
|
+
sharedExperiences: bond.sharedExperiences,
|
|
426
|
+
dependency: bond.dependency,
|
|
427
|
+
tick,
|
|
428
|
+
},
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|