@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,406 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/working.memory.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WorkingMemory — limited-capacity active buffer for current cognition.
|
|
7
|
+
*
|
|
8
|
+
* Holds:
|
|
9
|
+
* - Current percepts (from perceptual engines)
|
|
10
|
+
* - Active goals (from executive layer)
|
|
11
|
+
* - Retrieved episodic memories (from long-term store)
|
|
12
|
+
* - Current affective state
|
|
13
|
+
*
|
|
14
|
+
* Properties:
|
|
15
|
+
* - Capacity-limited (7 ± 2 chunks by default)
|
|
16
|
+
* - Rapid decay without rehearsal (items fade in ~2-10 seconds)
|
|
17
|
+
* - Attentional boost (attended items resist decay)
|
|
18
|
+
* - Chunking (related items can be grouped into single slots)
|
|
19
|
+
* - Recency effect (newest items displace oldest when at capacity)
|
|
20
|
+
*
|
|
21
|
+
* Receives modulation from:
|
|
22
|
+
* - SleepPressureRegulator (fatigue reduces capacity)
|
|
23
|
+
* - StressRegulator (overload reduces effective capacity)
|
|
24
|
+
* - CircadianOscillator (alertness modulates rehearsal strength)
|
|
25
|
+
*
|
|
26
|
+
* Part of Shard 0 — runs every tick, synchronous.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type {
|
|
30
|
+
Duration,
|
|
31
|
+
Tick,
|
|
32
|
+
SimulationContext,
|
|
33
|
+
ReadonlySimulationState,
|
|
34
|
+
StateCommands,
|
|
35
|
+
SimulationEvent,
|
|
36
|
+
} from '#core/types'
|
|
37
|
+
import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
|
|
38
|
+
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
39
|
+
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
40
|
+
import { GenerativeModel } from '#cognition/generative.model'
|
|
41
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
42
|
+
|
|
43
|
+
export interface WorkingMemoryConfig {
|
|
44
|
+
/** Maximum chunks in working memory (default 7, Miller's Law) */
|
|
45
|
+
maxChunks?: number
|
|
46
|
+
/** Base decay rate per second (0-1, fraction of activation lost) */
|
|
47
|
+
baseDecayRate?: number
|
|
48
|
+
/** How much attention focus slows decay (0-1, 0 = no protection) */
|
|
49
|
+
attentionProtection?: number
|
|
50
|
+
/** Threshold below which an item is dropped */
|
|
51
|
+
retrievalThreshold?: number
|
|
52
|
+
/** Whether to emit detailed WM events */
|
|
53
|
+
emitEvents?: boolean
|
|
54
|
+
bus?: CognitiveBus
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface WMItem {
|
|
58
|
+
id: string
|
|
59
|
+
type: string // 'percept', 'goal', 'memory', 'thought'
|
|
60
|
+
content: unknown
|
|
61
|
+
activation: number // 0-1: current activation strength
|
|
62
|
+
attendedAt: Tick[] // recent ticks where this item had attention
|
|
63
|
+
createdAt: Tick
|
|
64
|
+
sourceEntityId?: string
|
|
65
|
+
tags: string[]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
69
|
+
readonly name = 'working-memory'
|
|
70
|
+
|
|
71
|
+
private _maxChunks: number
|
|
72
|
+
private _baseDecayRate: number
|
|
73
|
+
private _attentionProtection: number
|
|
74
|
+
private _retrievalThreshold: number
|
|
75
|
+
private _emitEvents: boolean
|
|
76
|
+
|
|
77
|
+
private _items: WMItem[] = []
|
|
78
|
+
private _modulatedCapacity: number
|
|
79
|
+
private _currentFocusId: string | null = null
|
|
80
|
+
private _activeGoalCount = 0
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Monotonic suffix counter for injected WM item ids. Replaces Math.random()
|
|
84
|
+
* AND the former `Date.now()` component so a run replays identically (R2).
|
|
85
|
+
* Unique per engine instance, which is sufficient for WM item ids.
|
|
86
|
+
*/
|
|
87
|
+
private _idSeq = 0
|
|
88
|
+
|
|
89
|
+
private _bus: CognitiveBus | null = null
|
|
90
|
+
private readonly _model = new GenerativeModel()
|
|
91
|
+
|
|
92
|
+
constructor( config: WorkingMemoryConfig = {} ){
|
|
93
|
+
this._bus = config.bus ?? null
|
|
94
|
+
this._maxChunks = config.maxChunks ?? 7
|
|
95
|
+
this._baseDecayRate = config.baseDecayRate ?? 0.08
|
|
96
|
+
this._attentionProtection = config.attentionProtection ?? 0.6
|
|
97
|
+
this._retrievalThreshold = config.retrievalThreshold ?? 0.05
|
|
98
|
+
this._emitEvents = config.emitEvents ?? false
|
|
99
|
+
this._modulatedCapacity = this._maxChunks
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
attachBus( bus: CognitiveBus ): void { this._bus = bus }
|
|
103
|
+
|
|
104
|
+
// ── Engine interface ─────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
subscribes(): string[] {
|
|
108
|
+
return [
|
|
109
|
+
'attention.focus.changed',
|
|
110
|
+
'goal.state.changed',
|
|
111
|
+
'executive.prediction.formed',
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
publishes(): CognitiveEventSchema[] { return [] }
|
|
115
|
+
|
|
116
|
+
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
117
|
+
this._model.observe( e.type, e.salience )
|
|
118
|
+
switch( e.type ){
|
|
119
|
+
case 'attention.focus.changed': {
|
|
120
|
+
const p = e.payload as Record<string, unknown>
|
|
121
|
+
const focusId = p['entityId'] as string | undefined
|
|
122
|
+
if( focusId ) this._currentFocusId = focusId
|
|
123
|
+
const capacity = p['capacity'] as number | undefined
|
|
124
|
+
if( capacity != null ) this._modulatedCapacity = Math.round( capacity * this._maxChunks )
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
case 'goal.state.changed': {
|
|
128
|
+
const p = e.payload as Record<string, number>
|
|
129
|
+
if( p['activeCount'] != null ) this._activeGoalCount = p['activeCount']
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
case 'executive.prediction.formed': {
|
|
133
|
+
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
134
|
+
if( p.predictedDomains.includes('memory') )
|
|
135
|
+
this._model.setPrecision( 'memory.working.load', 1.0 + p.confidence * 0.5 )
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
snapshot(): Record<string, unknown> {
|
|
142
|
+
return {
|
|
143
|
+
items: this._items.length,
|
|
144
|
+
modulatedCap: this._modulatedCapacity,
|
|
145
|
+
focusId: this._currentFocusId,
|
|
146
|
+
activeGoals: this._activeGoalCount,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ── Public API ───────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
/** Returns all active WM items sorted by activation descending. */
|
|
153
|
+
getItems(): WMItem[] {
|
|
154
|
+
return [ ...this._items ].sort( ( a, b ) => b.activation - a.activation )
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Returns all active WM items of a given type, sorted by activation descending. */
|
|
158
|
+
getItemsByType( type: string ): WMItem[] {
|
|
159
|
+
return this._items
|
|
160
|
+
.filter( i => i.type === type )
|
|
161
|
+
.sort( ( a, b ) => b.activation - a.activation )
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Inject an item directly (used by integration tests and episodic retrieval). */
|
|
165
|
+
load( item: Omit<WMItem, 'id' | 'createdAt'> & { createdAt?: Tick } ): void {
|
|
166
|
+
const id = `wm-${( this._idSeq++ ).toString( 36 )}`
|
|
167
|
+
const createdAt = item.createdAt ?? 0
|
|
168
|
+
this._evictIfNeeded()
|
|
169
|
+
this._items.push({ ...item, id, createdAt })
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Effective config = base engine-config-working-memory ⊕ persona-prior (single-source).
|
|
174
|
+
* No-op at boot: mirror params equal the constructor defaults (reconciled in #83).
|
|
175
|
+
*/
|
|
176
|
+
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
177
|
+
const p = readEffectiveParams( state, 'engine-config-working-memory' )
|
|
178
|
+
if( p.maxChunks != null ) this._maxChunks = p.maxChunks
|
|
179
|
+
if( p.baseDecayRate != null ) this._baseDecayRate = p.baseDecayRate
|
|
180
|
+
if( p.attentionProtection != null ) this._attentionProtection = p.attentionProtection
|
|
181
|
+
if( p.retrievalThreshold != null ) this._retrievalThreshold = p.retrievalThreshold
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async react(
|
|
185
|
+
delta: Duration,
|
|
186
|
+
tick: Tick,
|
|
187
|
+
state: ReadonlySimulationState,
|
|
188
|
+
_context: SimulationContext
|
|
189
|
+
): Promise<EngineResult> {
|
|
190
|
+
const commands: StateCommands = { set: [], delete: [], metrics: [] }
|
|
191
|
+
const events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = []
|
|
192
|
+
|
|
193
|
+
// Effective config = base engine-config-working-memory ⊕ persona-prior (single-source).
|
|
194
|
+
this._readConfigFromState( state )
|
|
195
|
+
|
|
196
|
+
// Effective capacity: modulated by fatigue / stress signals from state
|
|
197
|
+
const fatigue = state.metrics.get('modulation.sleep_fatigue') ?? 0
|
|
198
|
+
const stress = state.metrics.get('modulation.stress_overload') ?? 0
|
|
199
|
+
const alertness = 1 - Math.max( fatigue, stress ) * 0.4
|
|
200
|
+
this._modulatedCapacity = Math.max( 3, Math.round( this._maxChunks * alertness ) )
|
|
201
|
+
|
|
202
|
+
// Ingest new content from state
|
|
203
|
+
this._ingestPercepts( state, tick )
|
|
204
|
+
this._ingestGoals( state, tick )
|
|
205
|
+
|
|
206
|
+
// Apply attention focus — boosts attendedAt for the currently focused item
|
|
207
|
+
this._applyAttention( state, tick )
|
|
208
|
+
|
|
209
|
+
// Decay all items
|
|
210
|
+
const deltaSeconds = delta / 1000
|
|
211
|
+
for( const item of this._items ){
|
|
212
|
+
const isAttended = item.attendedAt.includes( tick - 1 )
|
|
213
|
+
const decayRate = isAttended
|
|
214
|
+
? this._baseDecayRate * ( 1 - this._attentionProtection )
|
|
215
|
+
: this._baseDecayRate
|
|
216
|
+
item.activation = Math.max( 0, item.activation - decayRate * deltaSeconds )
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Active rehearsal — items with sustained attention resist decay
|
|
220
|
+
this._rehearseItems()
|
|
221
|
+
|
|
222
|
+
// Drop items below threshold
|
|
223
|
+
const before = this._items.length
|
|
224
|
+
this._items = this._items.filter( i => i.activation >= this._retrievalThreshold )
|
|
225
|
+
const dropped = before - this._items.length
|
|
226
|
+
|
|
227
|
+
// Persist items as state entities + clean up stale ones
|
|
228
|
+
this._persistItems( tick, state, commands )
|
|
229
|
+
|
|
230
|
+
// Metrics
|
|
231
|
+
const load = this._items.length / this._maxChunks
|
|
232
|
+
commands.metrics!.push(
|
|
233
|
+
[ 'memory.working.load', load ],
|
|
234
|
+
[ 'memory.working.capacity', this._modulatedCapacity ],
|
|
235
|
+
[ 'memory.working.items', this._items.length ],
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
// Bus events
|
|
239
|
+
if( this._bus ){
|
|
240
|
+
this._bus.publish({
|
|
241
|
+
type: 'memory.working.changed',
|
|
242
|
+
version: 1,
|
|
243
|
+
sourceEngine: this.name,
|
|
244
|
+
salience: this._model.observe( 'memory.working.load', load ).salience,
|
|
245
|
+
payload: { items: this._items.length, capacity: this._modulatedCapacity, load },
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
if( this._emitEvents && this._items.length >= this._modulatedCapacity ){
|
|
249
|
+
this._bus.publish({
|
|
250
|
+
type: 'working_memory.full',
|
|
251
|
+
version: 1,
|
|
252
|
+
sourceEngine: this.name,
|
|
253
|
+
salience: 0.7,
|
|
254
|
+
payload: { capacity: this._modulatedCapacity, items: this._items.length },
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if( this._emitEvents && dropped > 0 ){
|
|
260
|
+
events.push({
|
|
261
|
+
type: 'working.memory.overflow',
|
|
262
|
+
source: this.name,
|
|
263
|
+
payload: { dropped, remaining: this._items.length },
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return { events: events.length > 0 ? events : undefined, commands }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ── Internal ─────────────────────────────────────────────
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Read the latest percept entities from state and inject them as WM items.
|
|
274
|
+
* Skips generic placeholder summaries to avoid noise.
|
|
275
|
+
*/
|
|
276
|
+
private _ingestPercepts( state: ReadonlySimulationState, tick: Tick ): void {
|
|
277
|
+
for( const entity of state.entities.values() ){
|
|
278
|
+
if( entity.type !== 'percept' ) continue
|
|
279
|
+
if( this._items.some( i => i.sourceEntityId === entity.id ) ) continue
|
|
280
|
+
|
|
281
|
+
const summary = ( entity.metadata?.summary ?? entity.metadata?.content ?? '' ) as string
|
|
282
|
+
if( !summary || summary.startsWith('New percept:') ) continue
|
|
283
|
+
|
|
284
|
+
this._evictIfNeeded()
|
|
285
|
+
this._items.push({
|
|
286
|
+
id: `wm-percept-${entity.id}`,
|
|
287
|
+
type: 'percept',
|
|
288
|
+
content: { summary, entityId: entity.id },
|
|
289
|
+
activation: 0.75,
|
|
290
|
+
attendedAt: [],
|
|
291
|
+
createdAt: tick,
|
|
292
|
+
sourceEntityId: entity.id,
|
|
293
|
+
tags: [ 'percept', ...(( entity.metadata?.tags as string[] ) ?? []) ],
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Read active goal entities from state and ensure each has a WM slot.
|
|
300
|
+
* Goal items start at 0.65 activation — lower than percepts, higher than background.
|
|
301
|
+
*/
|
|
302
|
+
private _ingestGoals( state: ReadonlySimulationState, tick: Tick ): void {
|
|
303
|
+
for( const entity of state.entities.values() ){
|
|
304
|
+
if( entity.type !== 'goal' ) continue
|
|
305
|
+
if( entity.metadata?.status !== 'active' ) continue
|
|
306
|
+
if( this._items.some( i => i.sourceEntityId === entity.id ) ) continue
|
|
307
|
+
|
|
308
|
+
this._evictIfNeeded()
|
|
309
|
+
this._items.push({
|
|
310
|
+
id: `wm-goal-${entity.id}`,
|
|
311
|
+
type: 'goal',
|
|
312
|
+
content: {
|
|
313
|
+
description: entity.metadata?.description ?? entity.metadata?.name ?? entity.id,
|
|
314
|
+
priority: entity.metadata?.priority ?? 0.5,
|
|
315
|
+
},
|
|
316
|
+
activation: 0.65,
|
|
317
|
+
attendedAt: [],
|
|
318
|
+
createdAt: tick,
|
|
319
|
+
sourceEntityId: entity.id,
|
|
320
|
+
tags: [ 'goal', 'executive' ],
|
|
321
|
+
})
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Mark the currently focused entity's WM item as attended this tick.
|
|
327
|
+
* Also checks for attention.focus entities in state as a fallback.
|
|
328
|
+
*/
|
|
329
|
+
private _applyAttention( state: ReadonlySimulationState, tick: Tick ): void {
|
|
330
|
+
// Bus-driven focus (preferred)
|
|
331
|
+
if( this._currentFocusId ){
|
|
332
|
+
const item = this._items.find( i => i.sourceEntityId === this._currentFocusId )
|
|
333
|
+
if( item && !item.attendedAt.includes( tick ) ) item.attendedAt.push( tick )
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// State-entity fallback: attention.focus entities
|
|
337
|
+
for( const entity of state.entities.values() ){
|
|
338
|
+
if( entity.type !== 'attention.focus' ) continue
|
|
339
|
+
const targetId = entity.metadata?.targetEntityId as string | undefined
|
|
340
|
+
if( !targetId ) continue
|
|
341
|
+
const item = this._items.find( i => i.sourceEntityId === targetId )
|
|
342
|
+
if( item && !item.attendedAt.includes( tick ) ) item.attendedAt.push( tick )
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Trim attendedAt history to last 20 ticks to avoid unbounded growth
|
|
346
|
+
for( const item of this._items ){
|
|
347
|
+
if( item.attendedAt.length > 20 )
|
|
348
|
+
item.attendedAt = item.attendedAt.slice( -20 )
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Items that have been attended 3+ times receive a small activation boost
|
|
354
|
+
* — simulating active rehearsal keeping them in working memory.
|
|
355
|
+
*/
|
|
356
|
+
private _rehearseItems(): void {
|
|
357
|
+
for( const item of this._items ){
|
|
358
|
+
if( item.attendedAt.length >= 3 )
|
|
359
|
+
item.activation = Math.min( 1, item.activation + 0.02 )
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Write each live WM item as a state entity so downstream engines can read them,
|
|
365
|
+
* and delete any stale WM entities that no longer correspond to live items.
|
|
366
|
+
*/
|
|
367
|
+
private _persistItems( tick: Tick, state: ReadonlySimulationState, commands: StateCommands ): void {
|
|
368
|
+
const liveIds = new Set<string>()
|
|
369
|
+
|
|
370
|
+
for( const item of this._items ){
|
|
371
|
+
const entityId = `wm-item-${item.id}`
|
|
372
|
+
liveIds.add( entityId )
|
|
373
|
+
commands.set!.push({
|
|
374
|
+
id: entityId,
|
|
375
|
+
type: 'working_memory.item',
|
|
376
|
+
metadata: {
|
|
377
|
+
wmType: item.type,
|
|
378
|
+
content: item.content,
|
|
379
|
+
activation: item.activation,
|
|
380
|
+
attendedCount: item.attendedAt.length,
|
|
381
|
+
tags: item.tags,
|
|
382
|
+
tick
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Remove stale WM entities from state that are no longer in the live item set
|
|
388
|
+
// (entities written in a previous tick whose item has since decayed)
|
|
389
|
+
for( const entity of state.entities.values() ){
|
|
390
|
+
if( entity.type === 'working_memory.item' && !liveIds.has( entity.id ) ){
|
|
391
|
+
commands.delete!.push( entity.id )
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private _evictIfNeeded(): void {
|
|
397
|
+
if( this._items.length < this._modulatedCapacity ) return
|
|
398
|
+
let minIdx = 0
|
|
399
|
+
for( let i = 1; i < this._items.length; i++ ){
|
|
400
|
+
const cur = this._items[i]
|
|
401
|
+
const best = this._items[minIdx]
|
|
402
|
+
if( cur !== undefined && best !== undefined && cur.activation < best.activation ) minIdx = i
|
|
403
|
+
}
|
|
404
|
+
this._items.splice( minIdx, 1 )
|
|
405
|
+
}
|
|
406
|
+
}
|