@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,294 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/reputation.tracker.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ReputationTracker — maintains models of others' reliability,
|
|
7
|
+
* cooperativeness, and social standing.
|
|
8
|
+
*
|
|
9
|
+
* Tracks per-agent:
|
|
10
|
+
* - Reliability (did they do what they said they would?)
|
|
11
|
+
* - Cooperativeness (did they help or hinder?)
|
|
12
|
+
* - Social standing (how do others seem to regard them?)
|
|
13
|
+
* - Trustworthiness (composite of reliability + cooperativeness)
|
|
14
|
+
*
|
|
15
|
+
* Part of Shard 1 (Social Layer) — runs every tick, synchronous.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
Duration,
|
|
20
|
+
Tick,
|
|
21
|
+
SimulationContext,
|
|
22
|
+
ReadonlySimulationState,
|
|
23
|
+
StateCommands,
|
|
24
|
+
SimulationEvent,
|
|
25
|
+
} from '#core/types'
|
|
26
|
+
import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
|
|
27
|
+
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
28
|
+
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
29
|
+
import { GenerativeModel } from '#cognition/generative.model'
|
|
30
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
31
|
+
|
|
32
|
+
export interface ReputationTrackerConfig {
|
|
33
|
+
/** Maximum agents to track */
|
|
34
|
+
maxTrackedAgents?: number
|
|
35
|
+
/** How quickly reputation decays without new observations */
|
|
36
|
+
decayRate?: number
|
|
37
|
+
/** Minimum interactions before reputation is considered reliable */
|
|
38
|
+
minInteractions?: number
|
|
39
|
+
/** How much a cooperative interaction raises a tracked agent's cooperativeness (trust step) */
|
|
40
|
+
trustGrowthStep?: number
|
|
41
|
+
bus?: CognitiveBus
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface Reputation {
|
|
45
|
+
keid: string
|
|
46
|
+
reliability: number // 0-1: keeps promises
|
|
47
|
+
cooperativeness: number // 0-1: helps vs. hinders
|
|
48
|
+
socialStanding: number // 0-1: regarded by others
|
|
49
|
+
trustworthiness: number // 0-1: composite
|
|
50
|
+
interactionCount: number
|
|
51
|
+
positiveInteractions: number
|
|
52
|
+
negativeInteractions: number
|
|
53
|
+
lastInteractionTick: Tick
|
|
54
|
+
confidence: number // 0-1: how confident in this assessment
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class ReputationTracker implements SimulationEngine, CognitiveEngine {
|
|
58
|
+
readonly name = 'reputation-tracker'
|
|
59
|
+
|
|
60
|
+
private _maxTrackedAgents: number
|
|
61
|
+
private _decayRate: number
|
|
62
|
+
private _minInteractions: number
|
|
63
|
+
private _trustGrowthStep: number
|
|
64
|
+
|
|
65
|
+
private _reputations = new Map<string, Reputation>()
|
|
66
|
+
/** True after reputations have been rehydrated from persisted state on first tick. */
|
|
67
|
+
private _restored = false
|
|
68
|
+
private _pendingInteractions: Array<{
|
|
69
|
+
keid: string; valence: number; intensity: number; directedAtSelf: boolean
|
|
70
|
+
}> = []
|
|
71
|
+
|
|
72
|
+
private _bus: CognitiveBus | null = null
|
|
73
|
+
|
|
74
|
+
private readonly _model = new GenerativeModel()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
constructor( config: ReputationTrackerConfig = {} ){
|
|
78
|
+
this._bus = config.bus ?? null
|
|
79
|
+
this._maxTrackedAgents = config.maxTrackedAgents ?? 20
|
|
80
|
+
this._decayRate = config.decayRate ?? 0.001
|
|
81
|
+
this._minInteractions = config.minInteractions ?? 3
|
|
82
|
+
this._trustGrowthStep = config.trustGrowthStep ?? 0.05
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
attachBus( bus: CognitiveBus ): void { this._bus = bus }
|
|
86
|
+
|
|
87
|
+
// ── Engine interface ─────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
subscribes(): string[] {
|
|
90
|
+
return [
|
|
91
|
+
'executive.prediction.formed',
|
|
92
|
+
'interaction.occurred',
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
publishes(): CognitiveEventSchema[] { return [] }
|
|
97
|
+
|
|
98
|
+
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
99
|
+
this._model.observe( e.type, e.salience )
|
|
100
|
+
if( e.type === 'executive.prediction.formed' ){
|
|
101
|
+
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
102
|
+
if( p.predictedDomains.includes('social') )
|
|
103
|
+
this._model.setPrecision( 'reputation.tracked', 1.0 + p.confidence * 0.5 )
|
|
104
|
+
}
|
|
105
|
+
if( e.type === 'interaction.occurred' ){
|
|
106
|
+
const p = e.payload as { keid: string; valence: number; intensity: number; directedAtSelf: boolean }
|
|
107
|
+
this._pendingInteractions.push( p )
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
snapshot(): Record<string, unknown> { return {} }
|
|
112
|
+
|
|
113
|
+
async react(
|
|
114
|
+
_delta: Duration,
|
|
115
|
+
tick: Tick,
|
|
116
|
+
state: ReadonlySimulationState,
|
|
117
|
+
_context: SimulationContext
|
|
118
|
+
): Promise<EngineResult> {
|
|
119
|
+
const
|
|
120
|
+
events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
|
|
121
|
+
commands: StateCommands = { set: [], metrics: [] }
|
|
122
|
+
|
|
123
|
+
// Channel A (agreeableness → trust): how much a cooperative interaction raises an
|
|
124
|
+
// agent's cooperativeness is refreshed each tick as base ⊕ persona-prior. An agreeable
|
|
125
|
+
// Will develops a larger step — it extends benefit-of-the-doubt and credits cooperation
|
|
126
|
+
// more readily (the trust facet).
|
|
127
|
+
this._trustGrowthStep = readEffectiveParams( state, 'engine-config-reputation' ).trustGrowthStep ?? this._trustGrowthStep
|
|
128
|
+
|
|
129
|
+
// Rehydrate _reputations from persisted state on the first tick after
|
|
130
|
+
// construction / snapshot restore. Without this, every session restart
|
|
131
|
+
// begins with an empty reputation map and immediately overwrites all
|
|
132
|
+
// saved relationship data with zeros on the first persist cycle.
|
|
133
|
+
if( !this._restored ){
|
|
134
|
+
this._restoreFromState( state )
|
|
135
|
+
this._restored = true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 1. Drain buffered interactions to update reputations
|
|
139
|
+
for( const interaction of this._pendingInteractions.splice( 0 ) ){
|
|
140
|
+
const { keid, valence } = interaction
|
|
141
|
+
if( !keid || keid === 'agent-self') continue
|
|
142
|
+
|
|
143
|
+
const rep = this._getOrCreate( keid, tick )
|
|
144
|
+
|
|
145
|
+
rep.interactionCount++
|
|
146
|
+
rep.lastInteractionTick = tick
|
|
147
|
+
|
|
148
|
+
if( valence > 0 ){
|
|
149
|
+
rep.positiveInteractions++
|
|
150
|
+
rep.cooperativeness = Math.min( 1, rep.cooperativeness + this._trustGrowthStep )
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if( valence < -0.3 ){
|
|
154
|
+
rep.negativeInteractions++
|
|
155
|
+
rep.cooperativeness = Math.max( 0, rep.cooperativeness - 0.08 )
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Reliability proxy: strong positive valence → consistent/reliable behaviour;
|
|
159
|
+
// strong negative → deceptive/unreliable. The original used explicit `reliable`
|
|
160
|
+
// and `deceptive` metadata flags on percept entities; those aren't in interaction.occurred,
|
|
161
|
+
// so we use extreme valence as the best available signal.
|
|
162
|
+
if( valence > 0.7 )
|
|
163
|
+
rep.reliability = Math.min( 1, rep.reliability + 0.04 )
|
|
164
|
+
else if( valence < -0.7 )
|
|
165
|
+
rep.reliability = Math.max( 0, rep.reliability - 0.08 )
|
|
166
|
+
|
|
167
|
+
// Composite trustworthiness
|
|
168
|
+
rep.trustworthiness = ( rep.reliability * 0.5 + rep.cooperativeness * 0.5 )
|
|
169
|
+
|
|
170
|
+
// Confidence increases with more interactions
|
|
171
|
+
rep.confidence = Math.min( 1, rep.interactionCount / this._minInteractions )
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 2. Decay old reputations
|
|
175
|
+
for( const rep of this._reputations.values() ){
|
|
176
|
+
const ticksSince = tick - rep.lastInteractionTick
|
|
177
|
+
if( ticksSince > 200 ){
|
|
178
|
+
rep.confidence = Math.max( 0.05, rep.confidence - this._decayRate * ticksSince )
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 3. Prune
|
|
183
|
+
this._prune()
|
|
184
|
+
|
|
185
|
+
// 4. Persist
|
|
186
|
+
for( const rep of this._reputations.values() ){
|
|
187
|
+
if( rep.interactionCount === 0 ) continue
|
|
188
|
+
|
|
189
|
+
commands.set!.push({
|
|
190
|
+
id: `reputation-${rep.keid}`,
|
|
191
|
+
type: 'reputation',
|
|
192
|
+
metadata: {
|
|
193
|
+
keid: rep.keid,
|
|
194
|
+
reliability: rep.reliability,
|
|
195
|
+
cooperativeness: rep.cooperativeness,
|
|
196
|
+
socialStanding: rep.socialStanding,
|
|
197
|
+
trustworthiness: rep.trustworthiness,
|
|
198
|
+
interactionCount: rep.interactionCount,
|
|
199
|
+
positiveInteractions: rep.positiveInteractions,
|
|
200
|
+
negativeInteractions: rep.negativeInteractions,
|
|
201
|
+
lastInteractionTick: rep.lastInteractionTick,
|
|
202
|
+
confidence: rep.confidence,
|
|
203
|
+
tick,
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
commands.metrics!.push(
|
|
209
|
+
[ 'reputation.tracked_agents', this._reputations.size ],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
// Phase C + F: publish cognitive event — gated by prediction error
|
|
214
|
+
const _bus = this._bus
|
|
215
|
+
if( _bus && this._reputations.size > 0 ){
|
|
216
|
+
const predErr = this._model.observe( 'reputation.tracked', this._reputations.size )
|
|
217
|
+
if( !predErr.gated )
|
|
218
|
+
_bus.publish({ type: 'reputation.updated', version: 1, sourceEngine: this.name, salience: Math.max( 0.2, predErr.salience ), payload: { trackedAgents: this._reputations.size } })
|
|
219
|
+
}
|
|
220
|
+
return { events: events.length > 0 ? events : undefined, commands }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── Public API ───────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
getReputation( keid: string ): Reputation | undefined {
|
|
226
|
+
return this._reputations.get( keid )
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
isTrusted( keid: string, threshold: number = 0.5 ): boolean {
|
|
230
|
+
const rep = this._reputations.get( keid )
|
|
231
|
+
return ( rep?.trustworthiness ?? 0.5 ) >= threshold
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ── Internal ─────────────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Rehydrate _reputations from 'reputation' entities in state.
|
|
238
|
+
* Called once on the first tick after snapshot restore so that relationship
|
|
239
|
+
* models formed in previous sessions survive a server restart.
|
|
240
|
+
*/
|
|
241
|
+
private _restoreFromState( state: ReadonlySimulationState ): void {
|
|
242
|
+
for( const entity of state.entities.values() ){
|
|
243
|
+
if( entity.type !== 'reputation' ) continue
|
|
244
|
+
const m = entity.metadata ?? {}
|
|
245
|
+
const keid = m['keid'] as string | undefined
|
|
246
|
+
if( !keid ) continue
|
|
247
|
+
if( this._reputations.has( keid ) ) continue // prefer in-memory if already present
|
|
248
|
+
|
|
249
|
+
this._reputations.set( keid, {
|
|
250
|
+
keid,
|
|
251
|
+
reliability: ( m['reliability'] as number ) ?? 0.5,
|
|
252
|
+
cooperativeness: ( m['cooperativeness'] as number ) ?? 0.5,
|
|
253
|
+
socialStanding: ( m['socialStanding'] as number ) ?? 0.5,
|
|
254
|
+
trustworthiness: ( m['trustworthiness'] as number ) ?? 0.5,
|
|
255
|
+
interactionCount: ( m['interactionCount'] as number ) ?? 0,
|
|
256
|
+
positiveInteractions: ( m['positiveInteractions'] as number ) ?? 0,
|
|
257
|
+
negativeInteractions: ( m['negativeInteractions'] as number ) ?? 0,
|
|
258
|
+
lastInteractionTick: ( m['lastInteractionTick'] as number ) ?? 0,
|
|
259
|
+
confidence: ( m['confidence'] as number ) ?? 0.1,
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private _getOrCreate( keid: string, tick: Tick ): Reputation {
|
|
265
|
+
const existing = this._reputations.get( keid )
|
|
266
|
+
if( existing ) return existing
|
|
267
|
+
|
|
268
|
+
const rep: Reputation = {
|
|
269
|
+
keid,
|
|
270
|
+
reliability: 0.5,
|
|
271
|
+
cooperativeness: 0.5,
|
|
272
|
+
socialStanding: 0.5,
|
|
273
|
+
trustworthiness: 0.5,
|
|
274
|
+
interactionCount: 0,
|
|
275
|
+
positiveInteractions: 0,
|
|
276
|
+
negativeInteractions: 0,
|
|
277
|
+
lastInteractionTick: tick,
|
|
278
|
+
confidence: 0.1,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this._reputations.set( keid, rep )
|
|
282
|
+
return rep
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private _prune(): void {
|
|
286
|
+
if( this._reputations.size <= this._maxTrackedAgents ) return
|
|
287
|
+
|
|
288
|
+
const sorted = Array.from( this._reputations.entries() )
|
|
289
|
+
.sort( ( a, b ) => b[1].interactionCount - a[1].interactionCount )
|
|
290
|
+
|
|
291
|
+
for( const [ id ] of sorted.slice( this._maxTrackedAgents ) )
|
|
292
|
+
this._reputations.delete( id )
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/reward.evaluator.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RewardEvaluator — detects positive outcomes and progress.
|
|
7
|
+
*
|
|
8
|
+
* Evaluates:
|
|
9
|
+
* - Goal progress and completion
|
|
10
|
+
* - Positive social feedback
|
|
11
|
+
* - Resource gains
|
|
12
|
+
* - Novel discoveries (when safe)
|
|
13
|
+
*
|
|
14
|
+
* Produces: joy, satisfaction, excitement
|
|
15
|
+
*
|
|
16
|
+
* Joy = immediate positive outcome
|
|
17
|
+
* Satisfaction = goal completion / steady progress
|
|
18
|
+
* Excitement = anticipated positive outcome + high arousal
|
|
19
|
+
*
|
|
20
|
+
* Part of Shard 1 (Affective Layer) — runs every tick, synchronous.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
Duration,
|
|
25
|
+
Tick,
|
|
26
|
+
SimulationContext,
|
|
27
|
+
ReadonlySimulationState,
|
|
28
|
+
StateCommands,
|
|
29
|
+
} from '#core/types'
|
|
30
|
+
import type { SimulationEngine, CognitiveEngine, EngineResult } from '#cognition/types'
|
|
31
|
+
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
32
|
+
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
33
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
34
|
+
import { GenerativeModel } from '#cognition/generative.model'
|
|
35
|
+
|
|
36
|
+
export interface RewardEvaluatorConfig {
|
|
37
|
+
/** Weight for goal-related rewards */
|
|
38
|
+
goalWeight?: number
|
|
39
|
+
/** Weight for social rewards */
|
|
40
|
+
socialWeight?: number
|
|
41
|
+
/** Weight for resource gains */
|
|
42
|
+
resourceWeight?: number
|
|
43
|
+
/** Weight for discovery/novelty rewards */
|
|
44
|
+
discoveryWeight?: number
|
|
45
|
+
/**
|
|
46
|
+
* How fast the social reward signal decays per tick (0-1).
|
|
47
|
+
* Default 0.02 → social warmth fades to zero over ~50 ticks after last interaction.
|
|
48
|
+
*/
|
|
49
|
+
socialDecayRate?: number
|
|
50
|
+
/** How much each positive directed interaction warms the social reward (warmth intensity) */
|
|
51
|
+
socialWarmthBoost?: number
|
|
52
|
+
bus?: CognitiveBus
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class RewardEvaluator implements SimulationEngine, CognitiveEngine {
|
|
56
|
+
readonly name = 'reward-evaluator'
|
|
57
|
+
|
|
58
|
+
private _goalWeight: number
|
|
59
|
+
private _socialWeight: number
|
|
60
|
+
private _resourceWeight: number
|
|
61
|
+
private _discoveryWeight: number
|
|
62
|
+
private _socialDecayRate: number
|
|
63
|
+
private _socialWarmthBoost: number
|
|
64
|
+
/**
|
|
65
|
+
* How fast goal-reward signal decays per tick (0-1).
|
|
66
|
+
* Default 0.05 → a priority-1.0 goal reward fades to ~0 over ~20 ticks,
|
|
67
|
+
* giving a noticeable joy/satisfaction window after each completion.
|
|
68
|
+
*/
|
|
69
|
+
private _goalRewardDecayRate: number
|
|
70
|
+
|
|
71
|
+
// Domain state — updated per-event
|
|
72
|
+
private _cachedEnergyLevel: number = 50
|
|
73
|
+
private _cachedNovelty: number = 0
|
|
74
|
+
private _cachedFearLevel: number = 0
|
|
75
|
+
|
|
76
|
+
// Cached reward components
|
|
77
|
+
/** Transient goal-achievement signal — spiked by goal.achieved, decays each tick. */
|
|
78
|
+
private _cachedGoalReward: number = 0
|
|
79
|
+
/** Transient social warmth — boosted by interaction.occurred, decays each tick. */
|
|
80
|
+
private _cachedSocialReward: number = 0
|
|
81
|
+
/** Count of goals completed recently — decays gradually, feeds satisfaction formula. */
|
|
82
|
+
private _goalsCompletedRecently: number = 0
|
|
83
|
+
|
|
84
|
+
// Track previous goal states for future entity-event updates
|
|
85
|
+
private _previousGoalProgress = new Map<string, number>()
|
|
86
|
+
|
|
87
|
+
private _bus: CognitiveBus | null = null
|
|
88
|
+
|
|
89
|
+
private readonly _model = new GenerativeModel()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
constructor( config: RewardEvaluatorConfig = {} ){
|
|
93
|
+
this._bus = config.bus ?? null
|
|
94
|
+
this._goalWeight = config.goalWeight ?? 0.40
|
|
95
|
+
this._socialWeight = config.socialWeight ?? 0.25
|
|
96
|
+
this._resourceWeight = config.resourceWeight ?? 0.15
|
|
97
|
+
this._discoveryWeight = config.discoveryWeight ?? 0.20
|
|
98
|
+
this._socialDecayRate = config.socialDecayRate ?? 0.02
|
|
99
|
+
this._socialWarmthBoost = config.socialWarmthBoost ?? 0.4
|
|
100
|
+
this._goalRewardDecayRate = 0.05
|
|
101
|
+
}
|
|
102
|
+
attachBus( bus: CognitiveBus ): void { this._bus = bus }
|
|
103
|
+
|
|
104
|
+
// ── Engine interface ─────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","stress.state.changed","novelty.state.changed","executive.prediction.formed","interaction.occurred","goal.achieved","action.outcome"] }
|
|
107
|
+
publishes(): CognitiveEventSchema[] { return [] }
|
|
108
|
+
|
|
109
|
+
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
110
|
+
this._model.observe( e.type, e.salience )
|
|
111
|
+
|
|
112
|
+
switch( e.type ){
|
|
113
|
+
|
|
114
|
+
case 'energy.state.changed': {
|
|
115
|
+
const p = e.payload as { level: number }
|
|
116
|
+
this._cachedEnergyLevel = p.level ?? this._cachedEnergyLevel
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case 'sleep.state.changed':
|
|
121
|
+
// sleep pressure doesn't directly drive reward — absorbed for completeness
|
|
122
|
+
break
|
|
123
|
+
|
|
124
|
+
case 'stress.state.changed':
|
|
125
|
+
// stress payload doesn't carry reward-relevant data beyond what novelty provides
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
case 'novelty.state.changed': {
|
|
129
|
+
const p = e.payload as { novelty: number; fearLevel: number }
|
|
130
|
+
this._cachedNovelty = p.novelty ?? this._cachedNovelty
|
|
131
|
+
this._cachedFearLevel = p.fearLevel ?? this._cachedFearLevel
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
case 'executive.prediction.formed': {
|
|
136
|
+
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
137
|
+
if( p.predictedDomains.includes('energy') )
|
|
138
|
+
this._model.setPrecision('reward.value', 1.0 + p.confidence * 0.3)
|
|
139
|
+
break
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case 'interaction.occurred': {
|
|
143
|
+
// Social warmth — each directed positive interaction boosts social reward.
|
|
144
|
+
// Negative interactions dampen it. Capped at [0, 1]; decays via react().
|
|
145
|
+
const p = e.payload as { keid: string; valence: number; intensity: number; directedAtSelf: boolean }
|
|
146
|
+
if( p.directedAtSelf ){
|
|
147
|
+
const contribution = p.valence * Math.max( 0.3, p.intensity )
|
|
148
|
+
this._cachedSocialReward = Math.min( 1, Math.max( 0,
|
|
149
|
+
this._cachedSocialReward + contribution * this._socialWarmthBoost
|
|
150
|
+
))
|
|
151
|
+
this._model.observe( 'reward.social', this._cachedSocialReward )
|
|
152
|
+
}
|
|
153
|
+
break
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
case 'goal.achieved': {
|
|
157
|
+
// Goal completion — spike goal reward proportional to goal priority,
|
|
158
|
+
// and increment the goals-completed counter that feeds satisfaction.
|
|
159
|
+
// Both decay in react() so the joy/satisfaction window is ~15-20 ticks.
|
|
160
|
+
const p = e.payload as { goalId: string; priority: number; timeToComplete: number }
|
|
161
|
+
const priority = p.priority ?? 0.5
|
|
162
|
+
this._cachedGoalReward = Math.min( 1, this._cachedGoalReward + priority * 0.9 )
|
|
163
|
+
this._goalsCompletedRecently = Math.min( 2, this._goalsCompletedRecently + 1 )
|
|
164
|
+
this._model.observe( 'reward.goal', this._cachedGoalReward )
|
|
165
|
+
break
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
default:
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return this._computeAndEmit()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
snapshot(): Record<string, unknown> {
|
|
176
|
+
return {
|
|
177
|
+
cachedEnergyLevel: this._cachedEnergyLevel,
|
|
178
|
+
cachedNovelty: this._cachedNovelty,
|
|
179
|
+
cachedSocialReward: this._cachedSocialReward,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Effective config = base engine-config-reward ⊕ persona-prior (single-source).
|
|
185
|
+
* No-op at boot: mirror params equal the constructor defaults (reconciled in #83).
|
|
186
|
+
*/
|
|
187
|
+
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
188
|
+
const p = readEffectiveParams( state, 'engine-config-reward' )
|
|
189
|
+
if( p.goalWeight != null ) this._goalWeight = p.goalWeight
|
|
190
|
+
if( p.socialWeight != null ) this._socialWeight = p.socialWeight
|
|
191
|
+
if( p.resourceWeight != null ) this._resourceWeight = p.resourceWeight
|
|
192
|
+
if( p.discoveryWeight != null ) this._discoveryWeight = p.discoveryWeight
|
|
193
|
+
if( p.socialDecayRate != null ) this._socialDecayRate = p.socialDecayRate
|
|
194
|
+
// Channel A (agreeableness → warmth): each interaction warms more, and warmth lingers
|
|
195
|
+
// (socialDecayRate lowered). _socialWarmthBoost is the cached field the interaction
|
|
196
|
+
// handler reads (onCognitiveEvent has no state).
|
|
197
|
+
if( p.socialWarmthBoost != null ) this._socialWarmthBoost = p.socialWarmthBoost
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async react(
|
|
201
|
+
_delta: Duration,
|
|
202
|
+
_tick: Tick,
|
|
203
|
+
state: ReadonlySimulationState,
|
|
204
|
+
_ctx: SimulationContext,
|
|
205
|
+
): Promise<EngineResult> {
|
|
206
|
+
// Effective config = base engine-config-reward ⊕ persona-prior (single-source).
|
|
207
|
+
this._readConfigFromState( state )
|
|
208
|
+
|
|
209
|
+
// Decay social reward each tick so warmth fades naturally between interactions.
|
|
210
|
+
// With default rate 0.02: a social reward of 1.0 decays to ~0 over ~50 ticks.
|
|
211
|
+
if( this._cachedSocialReward > 0 )
|
|
212
|
+
this._cachedSocialReward = Math.max( 0, this._cachedSocialReward - this._socialDecayRate )
|
|
213
|
+
|
|
214
|
+
// Decay goal-reward signal each tick.
|
|
215
|
+
// Default rate 0.05: a priority-1.0 achievement fades to ~0 over ~20 ticks,
|
|
216
|
+
// giving a clear joy/satisfaction window after each completion.
|
|
217
|
+
if( this._cachedGoalReward > 0 )
|
|
218
|
+
this._cachedGoalReward = Math.max( 0, this._cachedGoalReward - this._goalRewardDecayRate )
|
|
219
|
+
|
|
220
|
+
// Decay the goals-completed counter (feeds satisfaction formula).
|
|
221
|
+
if( this._goalsCompletedRecently > 0 )
|
|
222
|
+
this._goalsCompletedRecently = Math.max( 0, this._goalsCompletedRecently - 0.08 )
|
|
223
|
+
|
|
224
|
+
// Re-emit emotion metrics every tick so the affective blender always has fresh values.
|
|
225
|
+
return { commands: this._computeAndEmit() }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ── Private helpers ──────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
private _computeResourceReward(): number {
|
|
231
|
+
const energyRatio = this._cachedEnergyLevel / 100
|
|
232
|
+
return energyRatio > 0.5
|
|
233
|
+
? ( energyRatio - 0.5 ) * 0.6
|
|
234
|
+
: 0
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private _computeDiscoveryReward(): number {
|
|
238
|
+
const safety = 1 - this._cachedFearLevel
|
|
239
|
+
return this._cachedNovelty * safety * 0.8
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private _computeAndEmit(): StateCommands {
|
|
243
|
+
const
|
|
244
|
+
goalReward = this._cachedGoalReward,
|
|
245
|
+
socialReward = this._cachedSocialReward,
|
|
246
|
+
resourceReward = this._computeResourceReward(),
|
|
247
|
+
discoveryReward = this._computeDiscoveryReward()
|
|
248
|
+
|
|
249
|
+
const rewardLevel
|
|
250
|
+
= goalReward * this._goalWeight
|
|
251
|
+
+ socialReward * this._socialWeight
|
|
252
|
+
+ resourceReward * this._resourceWeight
|
|
253
|
+
+ discoveryReward * this._discoveryWeight
|
|
254
|
+
|
|
255
|
+
const
|
|
256
|
+
joy = Math.min( 1,
|
|
257
|
+
goalReward * 0.5
|
|
258
|
+
+ socialReward * 0.3
|
|
259
|
+
+ resourceReward * 0.2
|
|
260
|
+
),
|
|
261
|
+
|
|
262
|
+
satisfaction = Math.min( 1,
|
|
263
|
+
goalReward * 0.6
|
|
264
|
+
+ this._goalsCompletedRecently * 0.4
|
|
265
|
+
),
|
|
266
|
+
|
|
267
|
+
excitement = Math.min( 1,
|
|
268
|
+
discoveryReward * 0.4
|
|
269
|
+
+ goalReward * 0.3
|
|
270
|
+
+ rewardLevel * 0.3
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
const commands: StateCommands = { metrics: [] }
|
|
274
|
+
|
|
275
|
+
commands.metrics!.push(
|
|
276
|
+
[ 'emotion.joy', joy ],
|
|
277
|
+
[ 'emotion.satisfaction', satisfaction ],
|
|
278
|
+
[ 'emotion.excitement', excitement ],
|
|
279
|
+
[ 'reward.level', rewardLevel ],
|
|
280
|
+
[ 'reward.goal', goalReward ],
|
|
281
|
+
[ 'reward.social', socialReward ],
|
|
282
|
+
[ 'reward.resource', resourceReward ],
|
|
283
|
+
[ 'reward.discovery', discoveryReward ],
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
const _bus = this._bus
|
|
287
|
+
if( _bus ){
|
|
288
|
+
// Option B: reward-prediction-error salience — a CHANGE in reward grabs the
|
|
289
|
+
// workspace, a fully-expected reward goes quiet (dopamine-RPE analogue),
|
|
290
|
+
// precision-modulated (set on 'reward.value'). observe() runs every tick so
|
|
291
|
+
// the baseline tracks; the one value is reused across the reward events.
|
|
292
|
+
const rewardSalience = this._model.observe( 'reward.value', rewardLevel ).salience
|
|
293
|
+
|
|
294
|
+
if( joy > 0.5 )
|
|
295
|
+
_bus.publish({ type: 'emotion.joy.peak', version: 1, sourceEngine: this.name, salience: rewardSalience, payload: { joy } })
|
|
296
|
+
if( joy > 0.6 )
|
|
297
|
+
_bus.publish({ type: 'emotion.joy.significant', version: 1, sourceEngine: this.name, salience: rewardSalience, payload: { joy, satisfaction, excitement, rewardLevel } })
|
|
298
|
+
if( goalReward > 0.8 )
|
|
299
|
+
_bus.publish({ type: 'reward.goal_significant', version: 1, sourceEngine: this.name, salience: rewardSalience, payload: { goalReward, satisfaction } })
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return commands
|
|
303
|
+
}
|
|
304
|
+
}
|