@mindot/will 0.5.0 → 0.7.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/dist/channels/discord.d.ts +1 -1
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/channels/whatsapp.js.map +1 -1
- package/dist/cli.js +998 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +998 -59
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/mcp/effectors.js.map +1 -1
- package/dist/{will-BDq-TMQr.d.ts → will-DAW0l-lY.d.ts} +90 -10
- package/package.json +1 -1
- package/src/channels/discord.ts +11 -11
- package/src/channels/roster.ts +1 -1
- package/src/channels/types.ts +1 -1
- package/src/channels/whatsapp.ts +25 -25
- package/src/cli.ts +20 -20
- package/src/cognition/acp.ts +28 -0
- package/src/cognition/agency/consequence.ts +174 -0
- package/src/cognition/agency/engines/action.selector.ts +333 -48
- package/src/cognition/agency/engines/affordance.synthesizer.ts +35 -16
- package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
- package/src/cognition/agency/engines/motor.schema.executor.ts +90 -14
- package/src/cognition/agency/engines/reafference.engine.ts +152 -23
- package/src/cognition/agency/execution.primitives.ts +13 -13
- package/src/cognition/agency/proactive.communicator.ts +1 -1
- package/src/cognition/agency/reconcile.learning.ts +10 -1
- package/src/cognition/agency/revocation.ts +79 -0
- package/src/cognition/agency/schemas/repertoire.ts +109 -9
- package/src/cognition/agency/selection.scoring.ts +32 -10
- package/src/cognition/agency/types.ts +9 -0
- package/src/cognition/bus.ts +2 -2
- package/src/cognition/completion.inbox.ts +1 -1
- package/src/cognition/config.mirror.entities.ts +5 -5
- package/src/cognition/event.log.ts +2 -2
- package/src/cognition/event.schemas.ts +67 -67
- package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
- package/src/cognition/faculties/affective.blender.ts +36 -4
- package/src/cognition/faculties/attachment.evaluator.ts +6 -6
- package/src/cognition/faculties/attention.allocator.ts +63 -8
- package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
- package/src/cognition/faculties/bias.detector.ts +7 -7
- package/src/cognition/faculties/circadian.oscillator.ts +3 -3
- package/src/cognition/faculties/confidence.calibrator.ts +7 -7
- package/src/cognition/faculties/dream.simulator.ts +5 -5
- package/src/cognition/faculties/empathy.simulator.ts +7 -7
- package/src/cognition/faculties/energy.regulator.ts +4 -4
- package/src/cognition/faculties/episodic.consolidator.ts +6 -6
- package/src/cognition/faculties/executive.engine/commands.ts +6 -6
- package/src/cognition/faculties/executive.engine/context.ts +42 -42
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
- package/src/cognition/faculties/executive.engine/engine.ts +25 -25
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
- package/src/cognition/faculties/executive.engine/facet.ts +18 -18
- package/src/cognition/faculties/executive.engine/gating.ts +2 -2
- package/src/cognition/faculties/executive.engine/messages.ts +3 -3
- package/src/cognition/faculties/executive.engine/parser.ts +11 -11
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
- package/src/cognition/faculties/exteroception.ts +99 -5
- package/src/cognition/faculties/forgetting.curve.ts +3 -3
- package/src/cognition/faculties/frustration.evaluator.ts +6 -6
- package/src/cognition/faculties/goal.manager.ts +15 -15
- package/src/cognition/faculties/inhibition.controller.ts +3 -3
- package/src/cognition/faculties/interoception.ts +3 -3
- package/src/cognition/faculties/introspection.engine.ts +3 -3
- package/src/cognition/faculties/known.entity.tracker.ts +15 -15
- package/src/cognition/faculties/loss.evaluator.ts +2 -2
- package/src/cognition/faculties/moral.evaluator.ts +4 -4
- package/src/cognition/faculties/novelty.detector.ts +4 -4
- package/src/cognition/faculties/persona.consolidator.ts +12 -12
- package/src/cognition/faculties/planning.engine/engine.ts +47 -47
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
- package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
- package/src/cognition/faculties/reputation.tracker.ts +6 -6
- package/src/cognition/faculties/reward.evaluator.ts +4 -4
- package/src/cognition/faculties/self.model.updater.ts +8 -8
- package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
- package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
- package/src/cognition/faculties/social.perception.ts +3 -3
- package/src/cognition/faculties/spaced.repetition.ts +2 -2
- package/src/cognition/faculties/stress.regulator.ts +27 -4
- package/src/cognition/faculties/task.switcher.ts +11 -6
- package/src/cognition/faculties/theory.of.mind.ts +6 -6
- package/src/cognition/faculties/threat.evaluator.ts +3 -3
- package/src/cognition/faculties/working.memory.ts +8 -8
- package/src/cognition/generative.model.ts +2 -2
- package/src/cognition/memory/vector.adapter.ts +5 -5
- package/src/cognition/memory/vector.content.ts +4 -4
- package/src/cognition/memory/vector.embedder.ts +9 -9
- package/src/cognition/persona.prior.ts +1 -1
- package/src/cognition/schema.registry.ts +2 -2
- package/src/cognition/senses/audition.engine/engine.ts +2 -2
- package/src/cognition/senses/base.sense.engine.ts +1 -1
- package/src/cognition/utilities/token.tracker.ts +5 -5
- package/src/core/abstracts.ts +1 -1
- package/src/core/completion.recorder.ts +2 -2
- package/src/core/serialization.ts +3 -3
- package/src/core/snapshot.manager.ts +1 -1
- package/src/core/state.manager.ts +1 -1
- package/src/core/utils.ts +1 -1
- package/src/host/boot.ts +30 -30
- package/src/host/utterances.ts +1 -1
- package/src/llm/index.ts +9 -9
- package/src/llm/summarizer.ts +4 -4
- package/src/llm/wire.contracts.ts +1 -1
- package/src/mcp/effectors.ts +10 -10
- package/src/mcp/server.ts +11 -11
- package/src/pma/eval.ts +1 -1
- package/src/pma/index.ts +21 -21
- package/src/runners/outreach.runner.ts +3 -3
- package/src/runners/social.runner.ts +1 -1
- package/src/runners/thin-shim.runner.ts +1 -1
- package/src/sdk/will.ts +5 -5
- package/src/serve/server.ts +12 -12
- package/src/stem/assembly.audit.ts +3 -3
- package/src/stem/guards/identity.coherence.ts +10 -10
- package/src/stem/guards/identity.guard.ts +22 -22
- package/src/stem/index.ts +26 -11
- package/src/stem/mind.ts +12 -12
- package/src/stem/policy/arbiter.ts +136 -0
- package/src/stem/policy/rule.table.ts +172 -0
- package/src/stem/policy/verdict.recorder.ts +0 -0
- package/src/stem/tracts/biography.writer.ts +3 -3
- package/src/stem/tracts/effector.controller.ts +383 -4
- package/src/stem/tracts/health.reporter.ts +1 -1
- package/src/stem/tracts/outbox.controller.ts +4 -0
- package/src/stem/tracts/outbox.writer.ts +4 -4
- package/src/stem/tracts/pma.controller.ts +1 -1
- package/src/stem/tracts/replay.controller.ts +10 -10
- package/src/stem/tracts/sensory.controller.ts +2 -2
- package/src/stem/tracts/session.logger.ts +4 -4
- package/src/stem/tracts/transport/socketio.transport.ts +7 -7
- package/src/stem/tracts/transport/stream.transport.ts +2 -2
- package/src/stem/tracts/transport.controller.ts +15 -15
|
@@ -128,12 +128,12 @@ export class AttachmentEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
128
128
|
|
|
129
129
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
130
130
|
this._model.observe( e.type, e.salience )
|
|
131
|
-
if( e.type === 'executive.prediction.formed'
|
|
131
|
+
if( e.type === 'executive.prediction.formed'){
|
|
132
132
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
133
133
|
if( p.predictedDomains.includes('social') )
|
|
134
|
-
this._model.setPrecision(
|
|
134
|
+
this._model.setPrecision('emotion.love', 1.0 + p.confidence * 0.5 )
|
|
135
135
|
}
|
|
136
|
-
if( e.type === 'interaction.occurred'
|
|
136
|
+
if( e.type === 'interaction.occurred'){
|
|
137
137
|
const p = e.payload as {
|
|
138
138
|
keid: string; valence: number; intensity: number
|
|
139
139
|
directedAtSelf: boolean; interactionType: string
|
|
@@ -146,7 +146,7 @@ export class AttachmentEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
146
146
|
sharedExperience: false,
|
|
147
147
|
})
|
|
148
148
|
}
|
|
149
|
-
if( e.type === 'social.agents.present'
|
|
149
|
+
if( e.type === 'social.agents.present'){
|
|
150
150
|
const p = e.payload as { activeAgents: number }
|
|
151
151
|
this._cachedActiveAgents = p.activeAgents
|
|
152
152
|
}
|
|
@@ -167,7 +167,7 @@ export class AttachmentEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
167
167
|
// Channel A (agreeableness → attachment): how fast bonds form is refreshed each tick as
|
|
168
168
|
// base ⊕ persona-prior. An agreeable Will develops a higher growth rate and bonds more
|
|
169
169
|
// readily. (Seed existed but was ignored.)
|
|
170
|
-
this._growthRate = readEffectiveParams( state, 'engine-config-attachment'
|
|
170
|
+
this._growthRate = readEffectiveParams( state, 'engine-config-attachment').attachmentGrowthRate ?? this._growthRate
|
|
171
171
|
|
|
172
172
|
// On the very first tick after construction (including snapshot restores),
|
|
173
173
|
// rehydrate _bonds from attachment.bond entities written by _persistBonds().
|
|
@@ -230,7 +230,7 @@ export class AttachmentEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
230
230
|
// Phase C: publish cognitive event
|
|
231
231
|
const _bus = this._bus
|
|
232
232
|
if( _bus && love > 0.5 ){
|
|
233
|
-
const predErr = this._model.observe(
|
|
233
|
+
const predErr = this._model.observe('emotion.love', love )
|
|
234
234
|
if( !predErr.gated )
|
|
235
235
|
_bus.publish({ type: 'emotion.love.significant', version: 1, sourceEngine: this.name, salience: Math.min(1, love), payload: { love } })
|
|
236
236
|
}
|
|
@@ -29,6 +29,7 @@ import type { CognitiveEngine, SimulationEngine, EngineResult } from '#cognition
|
|
|
29
29
|
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
30
30
|
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
31
31
|
import { GenerativeModel } from '#cognition/generative.model'
|
|
32
|
+
import { ACP_SELF_PRECISION } from '#cognition/acp'
|
|
32
33
|
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
33
34
|
|
|
34
35
|
export interface AttentionAllocatorConfig {
|
|
@@ -57,6 +58,25 @@ interface AttentionFocus {
|
|
|
57
58
|
// a choice it relaxes back to baseline, so focus/rest are transient unless
|
|
58
59
|
// renewed. Effort scales the ceiling, so vitals always win — you cannot focus
|
|
59
60
|
// past exhaustion (a collapsed ceiling leaves nothing to engage).
|
|
61
|
+
// ── ACP-P2 (ACTION_CONDITIONED_PREDICTION §3) — efferent anticipation ────────
|
|
62
|
+
/** Expected attention-usage swing right after our own enaction. */
|
|
63
|
+
const ACP_USAGE_UPLIFT = 0.15
|
|
64
|
+
/** Conservative anticipation confidence (plan of record: 0.3–0.5). */
|
|
65
|
+
const ACP_CONFIDENCE = 0.4
|
|
66
|
+
/**
|
|
67
|
+
* Self-caused precision: measurement showed that after a stable stretch the
|
|
68
|
+
* salience denominator (EW variance) collapses, so ANY deviation saturates
|
|
69
|
+
* salience at 1.0 and a conservative anticipation nudge is invisible there.
|
|
70
|
+
* The measurable lever at this seam is precision (salience = base × precision,
|
|
71
|
+
* executive precedent at 'executive.prediction.formed'): our own action's
|
|
72
|
+
* swing carries reduced attention-grabbing weight — below the workspace gate
|
|
73
|
+
* (WORKSPACE_THRESHOLD = 0.4) even when the base saturates. Restored
|
|
74
|
+
* explicitly after ONE observe (GenerativeModel's own mean-reversion is
|
|
75
|
+
* 0.02/observe ≈ 50 ticks — that lingering would suppress genuine world
|
|
76
|
+
* surprise arriving after our action, the exact failure the plan forbids).
|
|
77
|
+
*/
|
|
78
|
+
// (moved to #cognition/acp — shared across ACP-P2 consumers)
|
|
79
|
+
|
|
60
80
|
const EFFORT_BASELINE = 0.7 // homeostatic default utilization of the ceiling
|
|
61
81
|
const EFFORT_MIN = 0.4 // deepest voluntary stand-down (rest)
|
|
62
82
|
const EFFORT_MAX = 1.0 // full mobilization (focus)
|
|
@@ -90,6 +110,8 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
90
110
|
private _effort: number = EFFORT_BASELINE
|
|
91
111
|
/** A one-shot focus/rest request from the executive, applied next react(). */
|
|
92
112
|
private _effortRequest: number | null = null
|
|
113
|
+
/** ACP-P2: a self-caused precision attenuation is armed; react() restores after one observe. */
|
|
114
|
+
private _acpOneShot = false
|
|
93
115
|
|
|
94
116
|
private _bus: CognitiveBus | null = null
|
|
95
117
|
|
|
@@ -115,6 +137,8 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
115
137
|
'executive.prediction.formed',
|
|
116
138
|
'attention.regulate', // voluntary focus/rest from the executive (Option C)
|
|
117
139
|
'senses.*', // all sense percepts — salience feeds attention allocation
|
|
140
|
+
// ACP-P2: our own enactions — anticipate the attention swing they cause
|
|
141
|
+
'agency.enacted', 'agency.communicate', 'agency.invocation',
|
|
118
142
|
]
|
|
119
143
|
}
|
|
120
144
|
publishes(): CognitiveEventSchema[] { return [] }
|
|
@@ -132,23 +156,46 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
132
156
|
// Voluntary focus/rest (Option C). Clamp the requested set-point; react()
|
|
133
157
|
// applies it next tick and then decays it back toward baseline.
|
|
134
158
|
const t = (e.payload as Record<string,number>)['effortTarget']
|
|
135
|
-
if( typeof t === 'number'
|
|
159
|
+
if( typeof t === 'number')
|
|
136
160
|
this._effortRequest = Math.min( EFFORT_MAX, Math.max( EFFORT_MIN, t ) )
|
|
137
161
|
break
|
|
138
162
|
}
|
|
139
163
|
case 'executive.prediction.formed': {
|
|
140
164
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
141
165
|
if( p.predictedDomains.includes('attention') )
|
|
142
|
-
this._model.setPrecision(
|
|
166
|
+
this._model.setPrecision('attention.usage', 1.0 + p.confidence * 0.5 )
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
case 'agency.enacted':
|
|
170
|
+
case 'agency.communicate':
|
|
171
|
+
case 'agency.invocation': {
|
|
172
|
+
// ACP-P2, first consumer: we just acted — our own attention state is
|
|
173
|
+
// about to move BECAUSE of it (usage up, free fraction down). Pre-blend
|
|
174
|
+
// that expectation so the self-caused swing lands with low prediction
|
|
175
|
+
// error and doesn't fire `attention.state.changed` as surprise; the
|
|
176
|
+
// world's own deviations still do. One-shot by construction — the
|
|
177
|
+
// anticipation weight is consumed by each stream's next observe().
|
|
178
|
+
// Only the two streams whose errors are actually consumed (they gate
|
|
179
|
+
// the publish) are anticipated; `attention.entity.*` errors are
|
|
180
|
+
// discarded today, so anticipating them would be theater.
|
|
181
|
+
const usage = this._model.predict('attention.usage')
|
|
182
|
+
const free = this._model.predict('attention.free_fraction')
|
|
183
|
+
this._model.anticipate('attention.usage', Math.min( 1, usage + ACP_USAGE_UPLIFT ), ACP_CONFIDENCE )
|
|
184
|
+
this._model.anticipate('attention.free_fraction', Math.max( 0, free - ACP_USAGE_UPLIFT ), ACP_CONFIDENCE )
|
|
185
|
+
// The measurable half (see ACP_SELF_PRECISION): the next observe of
|
|
186
|
+
// each stream carries self-caused weight; react() restores after one.
|
|
187
|
+
this._model.setPrecision('attention.usage', ACP_SELF_PRECISION )
|
|
188
|
+
this._model.setPrecision('attention.free_fraction', ACP_SELF_PRECISION )
|
|
189
|
+
this._acpOneShot = true
|
|
143
190
|
break
|
|
144
191
|
}
|
|
145
192
|
default:
|
|
146
193
|
// senses.*.percept — use the event's pre-computed salience as an
|
|
147
194
|
// attention signal for the percept's source entity.
|
|
148
|
-
if( e.type.startsWith(
|
|
195
|
+
if( e.type.startsWith('senses.') ){
|
|
149
196
|
const percept = e.payload as { sourceEntityId?: string; salience?: number }
|
|
150
197
|
if( percept.sourceEntityId )
|
|
151
|
-
this._model.observe(
|
|
198
|
+
this._model.observe(`attention.entity.${percept.sourceEntityId}`, e.salience )
|
|
152
199
|
}
|
|
153
200
|
break
|
|
154
201
|
}
|
|
@@ -194,7 +241,7 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
194
241
|
const
|
|
195
242
|
energyLevel = this._energyLevel,
|
|
196
243
|
sleepPressure = this._sleepPressure,
|
|
197
|
-
arousal = state.metrics.get(
|
|
244
|
+
arousal = state.metrics.get('affect.arousal') ?? AROUSAL_REST,
|
|
198
245
|
energyFactor = energyLevel < 30 ? 0.3 + ( energyLevel / 30 ) * 0.7 : 1.0,
|
|
199
246
|
sleepFactor = sleepPressure > 40
|
|
200
247
|
? 1 - ( ( sleepPressure - 40 ) / 60 ) * 0.5
|
|
@@ -296,8 +343,16 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
296
343
|
// load — and thus usage — is steady; otherwise the budget would not move in a
|
|
297
344
|
// quiet mind.
|
|
298
345
|
if( _bus ){
|
|
299
|
-
const usageErr = this._model.observe(
|
|
300
|
-
const freeErr = this._model.observe(
|
|
346
|
+
const usageErr = this._model.observe('attention.usage', attentionUsage )
|
|
347
|
+
const freeErr = this._model.observe('attention.free_fraction', freeFraction )
|
|
348
|
+
// ACP-P2: the self-caused observe has happened — restore full precision
|
|
349
|
+
// immediately so a genuine world surprise NEXT tick is not dampened
|
|
350
|
+
// (the model's own mean-reversion would take ~50 observes).
|
|
351
|
+
if( this._acpOneShot ){
|
|
352
|
+
this._model.setPrecision('attention.usage', 1.0 )
|
|
353
|
+
this._model.setPrecision('attention.free_fraction', 1.0 )
|
|
354
|
+
this._acpOneShot = false
|
|
355
|
+
}
|
|
301
356
|
if( !usageErr.gated || !freeErr.gated )
|
|
302
357
|
_bus.publish({ type: 'attention.state.changed', version: 1, sourceEngine: this.name, salience: Math.max( usageErr.salience, freeErr.salience ), payload: { usage: attentionUsage, focusCount, capacity: effectiveCapacity, freeFraction } })
|
|
303
358
|
}
|
|
@@ -310,7 +365,7 @@ export class AttentionAllocator implements SimulationEngine, CognitiveEngine {
|
|
|
310
365
|
// Effective config = base engine-config-attention ⊕ persona-prior (single-source).
|
|
311
366
|
// The persona-consolidator lowers shiftInertia on belief-formation bias (edge 8)
|
|
312
367
|
// → attention shifts more readily, loosening the fixation that feeds the bias.
|
|
313
|
-
const p = readEffectiveParams( state, 'engine-config-attention'
|
|
368
|
+
const p = readEffectiveParams( state, 'engine-config-attention')
|
|
314
369
|
if( p.maxCapacity != null ) this._maxCapacity = p.maxCapacity
|
|
315
370
|
if( p.costPerFocus != null ) this._costPerFocus = p.costPerFocus
|
|
316
371
|
if( p.maxFoci != null ) this._maxFoci = p.maxFoci
|
|
@@ -107,7 +107,7 @@ export class AutobiographicalNarrator implements SimulationEngine, CognitiveEngi
|
|
|
107
107
|
case 'executive.prediction.formed': {
|
|
108
108
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
109
109
|
if( p.predictedDomains.includes('narrative') )
|
|
110
|
-
this._model.setPrecision(
|
|
110
|
+
this._model.setPrecision('narrative.change', 1.0 + p.confidence * 0.5 )
|
|
111
111
|
break
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -245,7 +245,7 @@ export class AutobiographicalNarrator implements SimulationEngine, CognitiveEngi
|
|
|
245
245
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
246
246
|
const _bus = this._bus
|
|
247
247
|
if( _bus && this._narrative.version > 0 ){
|
|
248
|
-
const predErr = this._model.observe(
|
|
248
|
+
const predErr = this._model.observe('narrative.change', narrativeSignificance )
|
|
249
249
|
if( !predErr.gated )
|
|
250
250
|
_bus.publish({ type: 'narrative.updated', version: 1, sourceEngine: this.name, salience: Math.max( 0.2, predErr.salience ), payload: { version: this._narrative.version, significance: narrativeSignificance } })
|
|
251
251
|
}
|
|
@@ -269,7 +269,7 @@ export class AutobiographicalNarrator implements SimulationEngine, CognitiveEngi
|
|
|
269
269
|
* re-narrates its life story sooner.
|
|
270
270
|
*/
|
|
271
271
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
272
|
-
const p = readEffectiveParams( state, 'engine-config-narrator'
|
|
272
|
+
const p = readEffectiveParams( state, 'engine-config-narrator')
|
|
273
273
|
if( p.minIntervalTicks != null ) this._minIntervalTicks = p.minIntervalTicks
|
|
274
274
|
if( p.maxNarrativeLength != null ) this._maxNarrativeLength = p.maxNarrativeLength
|
|
275
275
|
}
|
|
@@ -100,7 +100,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
100
100
|
case 'executive.prediction.formed': {
|
|
101
101
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
102
102
|
if( p.predictedDomains.includes('metacognition') )
|
|
103
|
-
this._model.setPrecision(
|
|
103
|
+
this._model.setPrecision('bias.novelty', 1.0 + p.confidence * 0.5 )
|
|
104
104
|
|
|
105
105
|
break
|
|
106
106
|
}
|
|
@@ -168,7 +168,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
168
168
|
// Surprise is driven by how many biases *this scan* surfaced, not the
|
|
169
169
|
// cumulative count (which only grows, then saturates against the prune
|
|
170
170
|
// cap — a near-constant the gate could never read as surprising).
|
|
171
|
-
const predErr = this._model.observe(
|
|
171
|
+
const predErr = this._model.observe('bias.novelty', newBiases.length )
|
|
172
172
|
if( !predErr.gated )
|
|
173
173
|
_bus.publish({
|
|
174
174
|
type: 'bias.detected',
|
|
@@ -193,7 +193,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
193
193
|
* mirror) and stays constructor-only to avoid a lossy numeric coercion.
|
|
194
194
|
*/
|
|
195
195
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
196
|
-
const p = readEffectiveParams( state, 'engine-config-bias-detector'
|
|
196
|
+
const p = readEffectiveParams( state, 'engine-config-bias-detector')
|
|
197
197
|
|
|
198
198
|
if( p.minDecisions != null ) this._minDecisions = p.minDecisions
|
|
199
199
|
if( p.scanIntervalTicks != null ) this._scanIntervalTicks = p.scanIntervalTicks
|
|
@@ -209,7 +209,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
209
209
|
// 1. Overgeneralization: high-confidence beliefs from few episodes
|
|
210
210
|
{
|
|
211
211
|
const
|
|
212
|
-
beliefs = [ ...state.entities.values() ].filter( e => e.type === 'belief'
|
|
212
|
+
beliefs = [ ...state.entities.values() ].filter( e => e.type === 'belief')
|
|
213
213
|
.map( e => ({
|
|
214
214
|
confidence: ( e.metadata?.['confidence'] as number ) ?? 0,
|
|
215
215
|
supportingEpisodes: ( e.metadata?.['supportingEpisodes'] as number ) ?? 0,
|
|
@@ -230,7 +230,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
230
230
|
// 2. Recency bias: check if decisions heavily weight recent memories
|
|
231
231
|
{
|
|
232
232
|
const allEpisodes = [ ...state.entities.values() ]
|
|
233
|
-
.filter( e => e.type === 'episodic_memory'
|
|
233
|
+
.filter( e => e.type === 'episodic_memory')
|
|
234
234
|
.map( e => ({ timestamp: ( e.metadata?.['tick'] as number ) ?? 0 }))
|
|
235
235
|
if( allEpisodes.length > 20 ){
|
|
236
236
|
// `e.timestamp` is an episode tick, so the recency window is 50 ticks.
|
|
@@ -281,7 +281,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
281
281
|
// bias-detection has a single home (introspection used to detect these too).
|
|
282
282
|
{
|
|
283
283
|
const decisions = [ ...state.entities.values() ]
|
|
284
|
-
.filter( e => e.type === 'decision.record'
|
|
284
|
+
.filter( e => e.type === 'decision.record')
|
|
285
285
|
.map( e => ({
|
|
286
286
|
actionType: ( e.metadata?.['actionType'] as string ) ?? 'unknown',
|
|
287
287
|
confidence: ( e.metadata?.['confidence'] as number ) ?? 0.5,
|
|
@@ -328,7 +328,7 @@ export class BiasDetector implements SimulationEngine, CognitiveEngine {
|
|
|
328
328
|
*/
|
|
329
329
|
private _executiveCorroborates( type: string ): boolean {
|
|
330
330
|
if( this._executiveNamedBiases.size === 0 ) return false
|
|
331
|
-
const norm = ( s: string ): string => s.toLowerCase().replace( /[^a-z]/g, ''
|
|
331
|
+
const norm = ( s: string ): string => s.toLowerCase().replace( /[^a-z]/g, '')
|
|
332
332
|
const t = norm( type )
|
|
333
333
|
for( const named of this._executiveNamedBiases ){
|
|
334
334
|
const n = norm( named )
|
|
@@ -79,10 +79,10 @@ export class CircadianOscillator implements SimulationEngine, CognitiveEngine {
|
|
|
79
79
|
|
|
80
80
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
81
81
|
this._model.observe( e.type, e.salience )
|
|
82
|
-
if( e.type === 'executive.prediction.formed'
|
|
82
|
+
if( e.type === 'executive.prediction.formed'){
|
|
83
83
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
84
84
|
if( p.predictedDomains.includes('circadian') )
|
|
85
|
-
this._model.setPrecision(
|
|
85
|
+
this._model.setPrecision('circadian.alertness', 1.0 + p.confidence * 0.5 )
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -249,7 +249,7 @@ export class CircadianOscillator implements SimulationEngine, CognitiveEngine {
|
|
|
249
249
|
_bus.publish({ type: 'circadian.alertness.shifted', version: 1, sourceEngine: this.name, salience: Math.abs(alertnessSignal - 0.5) * 0.6, payload: { alertness: alertnessSignal, phase: phaseLabel } })
|
|
250
250
|
// Phase D + F: rich state-change event — gated by prediction error
|
|
251
251
|
if( _bus ){
|
|
252
|
-
const predErr = this._model.observe(
|
|
252
|
+
const predErr = this._model.observe('circadian.alertness', alertnessSignal )
|
|
253
253
|
if( !predErr.gated )
|
|
254
254
|
_bus.publish({ type: 'circadian.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { alertness: alertnessSignal, timeOfDay, phaseCode, moodBaseline: moodSignal } })
|
|
255
255
|
}
|
|
@@ -97,7 +97,7 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
97
97
|
case 'executive.prediction.formed': {
|
|
98
98
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
99
99
|
if( p.predictedDomains.includes('metacognition') )
|
|
100
|
-
this._model.setPrecision(
|
|
100
|
+
this._model.setPrecision('metacognition.bias', 1.0 + p.confidence * 0.5 )
|
|
101
101
|
|
|
102
102
|
break
|
|
103
103
|
}
|
|
@@ -105,7 +105,7 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
105
105
|
// Pair the decision's predicted confidence against the realised outcome
|
|
106
106
|
// quality so per-domain over/under-confidence can be learned in react().
|
|
107
107
|
const p = e.payload as { domain?: string; confidence?: number; outcomeQuality?: number; tick?: number }
|
|
108
|
-
if( typeof p.confidence === 'number' && typeof p.outcomeQuality === 'number'
|
|
108
|
+
if( typeof p.confidence === 'number' && typeof p.outcomeQuality === 'number')
|
|
109
109
|
this.recordOutcome( p.domain ?? 'general', p.confidence, p.outcomeQuality, ( ( p.tick ?? 0 ) as Tick ) )
|
|
110
110
|
|
|
111
111
|
break
|
|
@@ -130,7 +130,7 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
130
130
|
restore( snap: Record<string, unknown> ): void {
|
|
131
131
|
if( !snap ) return
|
|
132
132
|
|
|
133
|
-
if( typeof snap.executiveFlaggedBiasCount === 'number'
|
|
133
|
+
if( typeof snap.executiveFlaggedBiasCount === 'number')
|
|
134
134
|
this._executiveFlaggedBiasCount = snap.executiveFlaggedBiasCount
|
|
135
135
|
|
|
136
136
|
if( Array.isArray( snap.records ) )
|
|
@@ -154,7 +154,7 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
154
154
|
if( !m ) return
|
|
155
155
|
|
|
156
156
|
for( const [ domain, bias ] of Object.entries( m ) )
|
|
157
|
-
if( typeof bias === 'number'
|
|
157
|
+
if( typeof bias === 'number')
|
|
158
158
|
this._domainBias.set( domain, bias )
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -195,7 +195,7 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
195
195
|
* tunables and lets a future persona-prior modulate calibration aggressiveness.
|
|
196
196
|
*/
|
|
197
197
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
198
|
-
const p = readEffectiveParams( state, 'engine-config-confidence'
|
|
198
|
+
const p = readEffectiveParams( state, 'engine-config-confidence')
|
|
199
199
|
|
|
200
200
|
if( p.minSamplesPerDomain != null ) this._minSamplesPerDomain = p.minSamplesPerDomain
|
|
201
201
|
if( p.calibrationRate != null ) this._calibrationRate = p.calibrationRate
|
|
@@ -286,13 +286,13 @@ export class ConfidenceCalibrator implements SimulationEngine, CognitiveEngine {
|
|
|
286
286
|
type: 'confidence.calibrated',
|
|
287
287
|
version: 1,
|
|
288
288
|
sourceEngine: this.name,
|
|
289
|
-
salience: Math.max( 0.2, this._model.observe(
|
|
289
|
+
salience: Math.max( 0.2, this._model.observe('calibration.event', overallBias ).salience ),
|
|
290
290
|
payload: { calibrationBias: overallBias }
|
|
291
291
|
})
|
|
292
292
|
|
|
293
293
|
// Phase D + F: rich state-change event — gated by prediction error
|
|
294
294
|
if( _bus ){
|
|
295
|
-
const predErr = this._model.observe(
|
|
295
|
+
const predErr = this._model.observe('metacognition.bias', overallBias )
|
|
296
296
|
if( !predErr.gated )
|
|
297
297
|
_bus.publish({
|
|
298
298
|
type: 'metacognition.state.changed',
|
|
@@ -87,13 +87,13 @@ export class DreamSimulator implements SimulationEngine, CognitiveEngine {
|
|
|
87
87
|
|
|
88
88
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
89
89
|
this._model.observe( e.type, e.salience )
|
|
90
|
-
if( e.type === 'executive.prediction.formed'
|
|
90
|
+
if( e.type === 'executive.prediction.formed'){
|
|
91
91
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
92
92
|
if( p.predictedDomains.includes('memory') )
|
|
93
|
-
this._model.setPrecision(
|
|
93
|
+
this._model.setPrecision('dream.reactivation', 1.0 + p.confidence * 0.5 )
|
|
94
94
|
}
|
|
95
|
-
if( e.type === 'sleep.begun'
|
|
96
|
-
if( e.type === 'sleep.ended'
|
|
95
|
+
if( e.type === 'sleep.begun') this._isSleeping = true
|
|
96
|
+
if( e.type === 'sleep.ended') this._isSleeping = false
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
snapshot(): Record<string, unknown> { return {} }
|
|
@@ -197,7 +197,7 @@ export class DreamSimulator implements SimulationEngine, CognitiveEngine {
|
|
|
197
197
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
198
198
|
const _bus = this._bus
|
|
199
199
|
if( _bus && reactivated > 0 ){
|
|
200
|
-
const predErr = this._model.observe(
|
|
200
|
+
const predErr = this._model.observe('dream.reactivation', reactivated )
|
|
201
201
|
if( !predErr.gated )
|
|
202
202
|
_bus.publish({ type: 'dream.active', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { reactivated } })
|
|
203
203
|
}
|
|
@@ -90,14 +90,14 @@ export class EmpathySimulator implements SimulationEngine, CognitiveEngine {
|
|
|
90
90
|
|
|
91
91
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
92
92
|
this._model.observe( e.type, e.salience )
|
|
93
|
-
if( e.type === 'executive.prediction.formed'
|
|
93
|
+
if( e.type === 'executive.prediction.formed'){
|
|
94
94
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
95
95
|
if( p.predictedDomains.includes('social') )
|
|
96
|
-
this._model.setPrecision(
|
|
96
|
+
this._model.setPrecision('empathy.active', 1.0 + p.confidence * 0.5 )
|
|
97
97
|
}
|
|
98
|
-
if( e.type === 'interaction.occurred'
|
|
98
|
+
if( e.type === 'interaction.occurred'){
|
|
99
99
|
const p = e.payload as { keid: string; valence: number; intensity: number; directedAtSelf: boolean }
|
|
100
|
-
if( p.keid && p.keid !== 'agent-self'
|
|
100
|
+
if( p.keid && p.keid !== 'agent-self')
|
|
101
101
|
this._pendingInteractions.push( p )
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -117,7 +117,7 @@ export class EmpathySimulator implements SimulationEngine, CognitiveEngine {
|
|
|
117
117
|
// Channel A (agreeableness → empathy): how strongly the Will resonates with others'
|
|
118
118
|
// emotions is refreshed each tick as base ⊕ persona-prior. An agreeable Will develops
|
|
119
119
|
// a higher resonance and feels others' states more. (Seed existed but was ignored.)
|
|
120
|
-
this._resonanceStrength = readEffectiveParams( state, 'engine-config-empathy'
|
|
120
|
+
this._resonanceStrength = readEffectiveParams( state, 'engine-config-empathy').resonanceStrength ?? this._resonanceStrength
|
|
121
121
|
|
|
122
122
|
if( !this._theoryOfMind ){
|
|
123
123
|
commands.metrics!.push([ 'empathy.active_models', 0 ])
|
|
@@ -183,7 +183,7 @@ export class EmpathySimulator implements SimulationEngine, CognitiveEngine {
|
|
|
183
183
|
// blender folds the vicarious valence/arousal into the blended PAD.
|
|
184
184
|
let vicariousValence = 0, vicariousArousal = 0
|
|
185
185
|
for( const es of empathicStates ){
|
|
186
|
-
const bond = ( state.entities.get(
|
|
186
|
+
const bond = ( state.entities.get(`bond-${es.targetKeid}`)?.metadata?.attachmentStrength as number ) ?? 0
|
|
187
187
|
const w = es.resonanceStrength * ( 1 + EMPATHY_BOND_AMPLIFY * bond )
|
|
188
188
|
vicariousValence += es.estimatedEmotion.valence * w
|
|
189
189
|
vicariousArousal += es.estimatedEmotion.arousal * w
|
|
@@ -217,7 +217,7 @@ export class EmpathySimulator implements SimulationEngine, CognitiveEngine {
|
|
|
217
217
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
218
218
|
const _bus = this._bus
|
|
219
219
|
if( _bus && empathicStates.length > 0 ){
|
|
220
|
-
const predErr = this._model.observe(
|
|
220
|
+
const predErr = this._model.observe('empathy.active', empathicStates.length )
|
|
221
221
|
if( !predErr.gated )
|
|
222
222
|
_bus.publish({ type: 'empathy.resonance', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { activeModels: empathicStates.length } })
|
|
223
223
|
}
|
|
@@ -93,10 +93,10 @@ export class EnergyRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
93
93
|
|
|
94
94
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
95
95
|
this._model.observe( e.type, e.salience )
|
|
96
|
-
if( e.type === 'executive.prediction.formed'
|
|
96
|
+
if( e.type === 'executive.prediction.formed'){
|
|
97
97
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
98
98
|
if( p.predictedDomains.includes('energy') )
|
|
99
|
-
this._model.setPrecision(
|
|
99
|
+
this._model.setPrecision('energy.level', 1.0 + p.confidence * 0.5 )
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -290,11 +290,11 @@ export class EnergyRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
290
290
|
// Phase C: publish cognitive event
|
|
291
291
|
const _bus = this._bus
|
|
292
292
|
if( _bus && newEnergy < 20 )
|
|
293
|
-
_bus.publish({ type: 'energy.level.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.8, this._model.observe(
|
|
293
|
+
_bus.publish({ type: 'energy.level.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.8, this._model.observe('energy.critical', 1 - newEnergy / 100 ).salience ), payload: { level: newEnergy } })
|
|
294
294
|
// Phase D + F: rich state-change event — gated by prediction error
|
|
295
295
|
if( _bus ){
|
|
296
296
|
const zoneCode = newEnergy < this._criticalThreshold ? 0 : newEnergy < this._lowThreshold ? 1 : 2
|
|
297
|
-
const predErr = this._model.observe(
|
|
297
|
+
const predErr = this._model.observe('energy.level', newEnergy )
|
|
298
298
|
if( !predErr.gated )
|
|
299
299
|
_bus.publish({ type: 'energy.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { level: newEnergy, zoneCode, stressLoad: state.metrics.get('stress.load') ?? 0, interoceptionComfort: state.metrics.get('interoception.comfort') ?? 0.5 } })
|
|
300
300
|
}
|
|
@@ -234,7 +234,7 @@ export class EpisodicConsolidator implements SimulationEngine, CognitiveEngine {
|
|
|
234
234
|
type: string,
|
|
235
235
|
tags: string[],
|
|
236
236
|
): EpisodicMemory['outcomeStatus'] => {
|
|
237
|
-
if( type === 'conversation.exchange'
|
|
237
|
+
if( type === 'conversation.exchange') return 'confirmed'
|
|
238
238
|
if( tags.includes('failed') || tags.includes('error') || tags.includes('timed_out') ) return 'failed'
|
|
239
239
|
if( tags.includes('completed') || tags.includes('success') || tags.includes('confirmed') ) return 'confirmed'
|
|
240
240
|
if( tags.includes('goal') || tags.includes('plan') ) return 'intended'
|
|
@@ -413,7 +413,7 @@ export class EpisodicConsolidator implements SimulationEngine, CognitiveEngine {
|
|
|
413
413
|
// facet chains await this inside prompt building, so an unbounded hang here
|
|
414
414
|
// stalls the mind's reasoning and everything downstream of it.
|
|
415
415
|
// WILL_RECALL_TIMEOUT_MS (default 5000) — read lazily for tests/live tuning.
|
|
416
|
-
const timeoutMs = parseInt( process.env.WILL_RECALL_TIMEOUT_MS ?? '5000'
|
|
416
|
+
const timeoutMs = parseInt( process.env.WILL_RECALL_TIMEOUT_MS ?? '5000')
|
|
417
417
|
let timer: ReturnType<typeof setTimeout> | undefined
|
|
418
418
|
const timedOut = Symbol('recall-timeout')
|
|
419
419
|
|
|
@@ -426,7 +426,7 @@ export class EpisodicConsolidator implements SimulationEngine, CognitiveEngine {
|
|
|
426
426
|
] ).finally( () => clearTimeout( timer ) )
|
|
427
427
|
|
|
428
428
|
if( results === timedOut ){
|
|
429
|
-
logger.warn(
|
|
429
|
+
logger.warn(`[EpisodicConsolidator] semanticQuery timed out after ${timeoutMs}ms — returning no recall (embedder slow/unreachable?)`)
|
|
430
430
|
return []
|
|
431
431
|
}
|
|
432
432
|
|
|
@@ -659,13 +659,13 @@ export class EpisodicConsolidator implements SimulationEngine, CognitiveEngine {
|
|
|
659
659
|
await this._vectorMemory.load()
|
|
660
660
|
if( this._vectorMemory.size === 0 && this._store.length > 0 ){
|
|
661
661
|
await this._vectorMemory.rebuildFromStore( this._store )
|
|
662
|
-
logger.info(
|
|
662
|
+
logger.info(`[episodic] vector index rebuilt with ${this._store.length} episodes`)
|
|
663
663
|
} else if( this._vectorMemory.size > 0 ){
|
|
664
|
-
logger.info(
|
|
664
|
+
logger.info(`[episodic] vector index loaded from disk (${this._vectorMemory.size} entries)`)
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
-
logger.info(
|
|
668
|
+
logger.info(`[episodic] restored ${this._store.length} episodes from snapshot`)
|
|
669
669
|
}
|
|
670
670
|
|
|
671
671
|
// ── Internal ─────────────────────────────────────────────
|
|
@@ -148,7 +148,7 @@ export function buildStateCommands(
|
|
|
148
148
|
const integrator = deps.semanticIntegrator
|
|
149
149
|
const bus = deps.bus
|
|
150
150
|
output.knownEntityUpdates.forEach( ( u, ui ) => {
|
|
151
|
-
if( !u.keid || u.keid === 'agent-self'
|
|
151
|
+
if( !u.keid || u.keid === 'agent-self') return
|
|
152
152
|
|
|
153
153
|
const facts = u.learned ?? []
|
|
154
154
|
facts.forEach( ( fact, fi ) => {
|
|
@@ -380,7 +380,7 @@ const COMMUNICATE_ACTION_TYPES = new Set([
|
|
|
380
380
|
function resolveKnownEntity( target: string, state: ReadonlySimulationState ): string | undefined {
|
|
381
381
|
const t = target.trim().toLowerCase()
|
|
382
382
|
for( const e of state.entities.values() ){
|
|
383
|
-
if( e.type !== 'known-entity'
|
|
383
|
+
if( e.type !== 'known-entity') continue
|
|
384
384
|
const m = e.metadata as Record<string, unknown> | undefined
|
|
385
385
|
const keid = typeof m?.['keid'] === 'string' ? m['keid'] as string : undefined
|
|
386
386
|
const name = typeof m?.['name'] === 'string' ? m['name'] as string : undefined
|
|
@@ -414,9 +414,9 @@ function buildIdeomotorIntents(
|
|
|
414
414
|
// the executive can only pre-activate what the situation actually offers.
|
|
415
415
|
const externalBySchema = new Map<string, string>()
|
|
416
416
|
for( const e of state.entities.values() ){
|
|
417
|
-
if( e.type !== 'affordance'
|
|
417
|
+
if( e.type !== 'affordance') continue
|
|
418
418
|
const m = e.metadata as Record<string, unknown> | undefined
|
|
419
|
-
if( m?.['source'] !== 'external'
|
|
419
|
+
if( m?.['source'] !== 'external') continue
|
|
420
420
|
const schema = typeof m['schema'] === 'string' ? m['schema'] as string : undefined
|
|
421
421
|
if( schema ) externalBySchema.set( schema.toLowerCase(), schema )
|
|
422
422
|
}
|
|
@@ -439,8 +439,8 @@ function buildIdeomotorIntents(
|
|
|
439
439
|
|
|
440
440
|
// A host ability the executive imagines enacting, with its conscious args.
|
|
441
441
|
const schema = externalBySchema.get( t )
|
|
442
|
-
if( !schema || seen.has(
|
|
443
|
-
seen.add(
|
|
442
|
+
if( !schema || seen.has(`ability:${ schema }`) ) continue
|
|
443
|
+
seen.add(`ability:${ schema }`)
|
|
444
444
|
const keid = action.target ? resolveKnownEntity( action.target, state ) : undefined
|
|
445
445
|
set.push({
|
|
446
446
|
id: `ideomotor-${ schema }${ keid ? `-${ keid }` : '' }`,
|