@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
package/src/pma/eval.ts
CHANGED
|
@@ -368,7 +368,7 @@ export class PMAEvalHarness {
|
|
|
368
368
|
let loadedTraits: Record<string, number> = {}
|
|
369
369
|
|
|
370
370
|
for( const entity of state.entities.values() ){
|
|
371
|
-
if( entity.type === 'will.identity'
|
|
371
|
+
if( entity.type === 'will.identity'){
|
|
372
372
|
loadedTraits = ( entity.metadata?.['traits'] as Record<string, number> ) ?? {}
|
|
373
373
|
break
|
|
374
374
|
}
|
package/src/pma/index.ts
CHANGED
|
@@ -345,7 +345,7 @@ export class PMADistiller {
|
|
|
345
345
|
*/
|
|
346
346
|
private _extractPersona( state: SimulationState ): PMASnapshot['persona'] {
|
|
347
347
|
const priorMeta = state.entities.get( PERSONA_PRIOR_ID )?.metadata as { priors?: Record<string, Record<string, number>> } | undefined
|
|
348
|
-
const calibMeta = state.entities.get(
|
|
348
|
+
const calibMeta = state.entities.get('calibration-state')?.metadata as { domainBias?: Record<string, number> } | undefined
|
|
349
349
|
|
|
350
350
|
const configPriors = priorMeta?.priors ?? {}
|
|
351
351
|
const calibrationBias = calibMeta?.domainBias ?? {}
|
|
@@ -358,7 +358,7 @@ export class PMADistiller {
|
|
|
358
358
|
|
|
359
359
|
private _extractIdentity( state: SimulationState ): PMAIdentity {
|
|
360
360
|
for( const entity of state.entities.values() ){
|
|
361
|
-
if( entity.type === 'will.identity'
|
|
361
|
+
if( entity.type === 'will.identity'){
|
|
362
362
|
const m = entity.metadata ?? {}
|
|
363
363
|
return {
|
|
364
364
|
prompt: ( m['prompt'] as string ) ?? '',
|
|
@@ -390,9 +390,9 @@ export class PMADistiller {
|
|
|
390
390
|
// If socialOrientation not explicitly set, infer from top actions
|
|
391
391
|
if( !enhanced.socialOrientation && behavioral.fingerprint.topActions.length > 0 ){
|
|
392
392
|
const topAction = behavioral.fingerprint.topActions[0] ?? ''
|
|
393
|
-
if( topAction.includes(
|
|
393
|
+
if( topAction.includes('social') || topAction.includes('talk') || topAction.includes('text') ){
|
|
394
394
|
enhanced.socialOrientation = 'gregarious'
|
|
395
|
-
} else if( topAction.includes(
|
|
395
|
+
} else if( topAction.includes('reflect') || topAction.includes('meditate') ){
|
|
396
396
|
enhanced.socialOrientation = 'reserved'
|
|
397
397
|
} else {
|
|
398
398
|
enhanced.socialOrientation = 'ambivert'
|
|
@@ -418,7 +418,7 @@ export class PMADistiller {
|
|
|
418
418
|
const raw: PMABelief[] = []
|
|
419
419
|
|
|
420
420
|
for( const entity of state.entities.values() ){
|
|
421
|
-
if( entity.type !== 'belief'
|
|
421
|
+
if( entity.type !== 'belief') continue
|
|
422
422
|
|
|
423
423
|
const m = entity.metadata ?? {}
|
|
424
424
|
raw.push({
|
|
@@ -446,11 +446,11 @@ export class PMADistiller {
|
|
|
446
446
|
const goals: PMAGoal[] = []
|
|
447
447
|
|
|
448
448
|
for( const entity of state.entities.values() ){
|
|
449
|
-
if( entity.type !== 'goal'
|
|
449
|
+
if( entity.type !== 'goal') continue
|
|
450
450
|
|
|
451
451
|
const m = entity.metadata ?? {}
|
|
452
452
|
const status = ( m['status'] as string ) ?? 'active'
|
|
453
|
-
if( status !== 'active' && status !== 'in_progress'
|
|
453
|
+
if( status !== 'active' && status !== 'in_progress') continue
|
|
454
454
|
|
|
455
455
|
goals.push({
|
|
456
456
|
id: entity.id,
|
|
@@ -459,7 +459,7 @@ export class PMADistiller {
|
|
|
459
459
|
progress: ( m['progress'] as number ) ?? 0,
|
|
460
460
|
status,
|
|
461
461
|
tags: ( m['tags'] as string[] ) ?? [],
|
|
462
|
-
completionType: ( m['completionType'] as 'metric' | 'action' | 'epistemic'
|
|
462
|
+
completionType: ( m['completionType'] as 'metric' | 'action' | 'epistemic') ?? 'epistemic',
|
|
463
463
|
completionCondition: ( m['completionCondition'] as string ) ?? undefined,
|
|
464
464
|
})
|
|
465
465
|
}
|
|
@@ -475,7 +475,7 @@ export class PMADistiller {
|
|
|
475
475
|
const digestTick = new Map<string, number>()
|
|
476
476
|
|
|
477
477
|
for( const entity of state.entities.values() ){
|
|
478
|
-
if( entity.type === 'attachment.bond'
|
|
478
|
+
if( entity.type === 'attachment.bond'){
|
|
479
479
|
const m = entity.metadata ?? {}
|
|
480
480
|
const keid = m['keid'] as string | undefined
|
|
481
481
|
if( !keid ) continue
|
|
@@ -492,7 +492,7 @@ export class PMADistiller {
|
|
|
492
492
|
stubs.set( keid, stub )
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
else if( entity.type === 'reputation'
|
|
495
|
+
else if( entity.type === 'reputation'){
|
|
496
496
|
const m = entity.metadata ?? {}
|
|
497
497
|
const keid = m['keid'] as string | undefined
|
|
498
498
|
if( !keid ) continue
|
|
@@ -512,7 +512,7 @@ export class PMADistiller {
|
|
|
512
512
|
stubs.set( keid, stub )
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
else if( entity.type === 'theory_of_mind'
|
|
515
|
+
else if( entity.type === 'theory_of_mind'){
|
|
516
516
|
const m = entity.metadata ?? {}
|
|
517
517
|
const keid = m['keid'] as string | undefined
|
|
518
518
|
if( !keid ) continue
|
|
@@ -526,15 +526,15 @@ export class PMADistiller {
|
|
|
526
526
|
stubs.set( keid, stub )
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
-
else if( entity.type === 'known-entity'
|
|
529
|
+
else if( entity.type === 'known-entity'){
|
|
530
530
|
const m = entity.metadata ?? {}
|
|
531
531
|
const keid = m['keid'] as string | undefined
|
|
532
532
|
if( !keid ) continue
|
|
533
533
|
|
|
534
534
|
const stub = stubs.get( keid ) ?? { keid }
|
|
535
|
-
if( !stub.agentName && typeof m['name'] === 'string'
|
|
535
|
+
if( !stub.agentName && typeof m['name'] === 'string') stub.agentName = m['name'] as string
|
|
536
536
|
stub.dossier = {
|
|
537
|
-
kind: ( m['kind'] as 'sentient' | 'thing'
|
|
537
|
+
kind: ( m['kind'] as 'sentient' | 'thing') ?? 'sentient',
|
|
538
538
|
name: ( m['name'] as string | undefined ),
|
|
539
539
|
familiarity: ( m['familiarity'] as number ) ?? 0,
|
|
540
540
|
valence: ( m['valence'] as number ) ?? 0,
|
|
@@ -550,7 +550,7 @@ export class PMADistiller {
|
|
|
550
550
|
// AuditionEngine memory sink + ProactiveCommunicator). The most recent
|
|
551
551
|
// exchange summary wins.
|
|
552
552
|
else if( entity.type === 'episodic_memory'
|
|
553
|
-
&& entity.metadata?.['sourceType'] === 'conversation.exchange'
|
|
553
|
+
&& entity.metadata?.['sourceType'] === 'conversation.exchange'){
|
|
554
554
|
const content = ( entity.metadata['content'] as Record<string, unknown> | undefined ) ?? {}
|
|
555
555
|
const keid = content['entityId'] as string | undefined
|
|
556
556
|
if( !keid ) continue
|
|
@@ -599,7 +599,7 @@ export class PMADistiller {
|
|
|
599
599
|
reactivity: 0.5,
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
const filePath = join( dataDir, 'wills', willId, 'profiles', 'emotional_biography.jsonl'
|
|
602
|
+
const filePath = join( dataDir, 'wills', willId, 'profiles', 'emotional_biography.jsonl')
|
|
603
603
|
if( !existsSync( filePath ) ) return { baseline: defaultBaseline, sessionsRead: 0 }
|
|
604
604
|
|
|
605
605
|
const summaries = _readLastNSummaries( filePath, 'session_summary', 5 )
|
|
@@ -673,7 +673,7 @@ export class PMADistiller {
|
|
|
673
673
|
impulsivity: 0.3,
|
|
674
674
|
}
|
|
675
675
|
|
|
676
|
-
const filePath = join( dataDir, 'wills', willId, 'profiles', 'behavioral.jsonl'
|
|
676
|
+
const filePath = join( dataDir, 'wills', willId, 'profiles', 'behavioral.jsonl')
|
|
677
677
|
if( !existsSync( filePath ) ) return { fingerprint: defaultFingerprint, sessionsRead: 0 }
|
|
678
678
|
|
|
679
679
|
const summaries = _readLastNSummaries( filePath, 'session_summary', 5 )
|
|
@@ -860,7 +860,7 @@ export class PMALoader {
|
|
|
860
860
|
|
|
861
861
|
// ── 3. Goals ──────────────────────────────────────────────
|
|
862
862
|
for( const g of pma.goals ){
|
|
863
|
-
if( g.status !== 'active' && g.status !== 'in_progress'
|
|
863
|
+
if( g.status !== 'active' && g.status !== 'in_progress') continue
|
|
864
864
|
|
|
865
865
|
cognition.goalManager.addGoal(
|
|
866
866
|
g.description,
|
|
@@ -882,8 +882,8 @@ export class PMALoader {
|
|
|
882
882
|
pma.emotionalBaseline.arousalProfile === 'calm' ? 0.30 :
|
|
883
883
|
0.45
|
|
884
884
|
|
|
885
|
-
sm.setMetric(
|
|
886
|
-
sm.setMetric(
|
|
885
|
+
sm.setMetric('affect.valence', valence )
|
|
886
|
+
sm.setMetric('affect.arousal', arousal )
|
|
887
887
|
|
|
888
888
|
// ── 5. Temperament (influences emotional set-point) ───────
|
|
889
889
|
const temperamentValence = pma.emotionalBaseline.temperamentValence
|
|
@@ -1068,7 +1068,7 @@ function _readLastNSummaries(
|
|
|
1068
1068
|
n: number
|
|
1069
1069
|
): Array<Record<string, unknown>> {
|
|
1070
1070
|
try {
|
|
1071
|
-
return readFileSync( filePath, 'utf8'
|
|
1071
|
+
return readFileSync( filePath, 'utf8')
|
|
1072
1072
|
.split('\n')
|
|
1073
1073
|
.filter( l => l.trim().length > 0 )
|
|
1074
1074
|
.map( l => { try { return JSON.parse(l) as Record<string, unknown> } catch { return null } })
|
|
@@ -111,8 +111,8 @@ async function main(): Promise<void> {
|
|
|
111
111
|
lastBlocked = g('agency.communicate.blocked')
|
|
112
112
|
|
|
113
113
|
if( tick % 10 === 0 ){
|
|
114
|
-
const goals = [ ...snap.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active'
|
|
115
|
-
const sent = [ ...snap.entities.values() ].filter( e => e.type === 'conversation.sent'
|
|
114
|
+
const goals = [ ...snap.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active').length
|
|
115
|
+
const sent = [ ...snap.entities.values() ].filter( e => e.type === 'conversation.sent').length
|
|
116
116
|
console.log(
|
|
117
117
|
`[t${tick}] v=${g('affect.valence').toFixed(2)} arousal=${g('affect.arousal').toFixed(2)} ` +
|
|
118
118
|
`frust=${g('emotion.frustration').toFixed(2)} energy=${g('energy.level').toFixed(0)} ` +
|
|
@@ -130,7 +130,7 @@ async function main(): Promise<void> {
|
|
|
130
130
|
const startedAt = Date.now()
|
|
131
131
|
while( true ){
|
|
132
132
|
const s = m.listWills().find( w => w.id === WILL_ID )
|
|
133
|
-
if( !s || s.status === 'archived'
|
|
133
|
+
if( !s || s.status === 'archived') break
|
|
134
134
|
if( s.tickCount >= END_TICK ) break
|
|
135
135
|
if( sawReactive && sawProactive ){ console.log('\n[scenario] both paths observed — wrapping up'); break }
|
|
136
136
|
if( Date.now() - startedAt > SAFETY_MS ){ console.log('\n[scenario] safety cap hit'); break }
|
|
@@ -134,7 +134,7 @@ async function main(): Promise<void> {
|
|
|
134
134
|
|
|
135
135
|
// Beliefs the Will formed ABOUT Dr. Chen (social cognition evidence)
|
|
136
136
|
const chenBeliefs = ( ( pma as { beliefs?: Array<{ statement?: string; content?: string }> } ).beliefs ?? [] )
|
|
137
|
-
.map( b => b.statement ?? b.content ?? ''
|
|
137
|
+
.map( b => b.statement ?? b.content ?? '')
|
|
138
138
|
.filter( s => /chen|she|her|researcher|observ/i.test( s ) )
|
|
139
139
|
.slice( 0, 6 )
|
|
140
140
|
if( chenBeliefs.length ){
|
|
@@ -26,7 +26,7 @@ const TICK_MS = parseInt( process.env.WILL_TICK_MS ?? '1000')
|
|
|
26
26
|
const MAX_TICKS = parseInt( process.env.WILL_MAX_TICKS ?? '0' )
|
|
27
27
|
const LOG_INTERVAL = parseInt( process.env.WILL_LOG_INTERVAL ?? '10' )
|
|
28
28
|
const RANDOM_SEED = parseInt( process.env.WILL_SEED ?? String( Date.now() ) )
|
|
29
|
-
const ANATOMY = ( process.env.WILL_ANATOMY ?? 'mind'
|
|
29
|
+
const ANATOMY = ( process.env.WILL_ANATOMY ?? 'mind') as WillConfig['anatomy']
|
|
30
30
|
const EXECUTIVE_INT = process.env.WILL_EXECUTIVE_INTERVAL
|
|
31
31
|
? parseInt( process.env.WILL_EXECUTIVE_INTERVAL )
|
|
32
32
|
: undefined
|
package/src/sdk/will.ts
CHANGED
|
@@ -362,7 +362,7 @@ export class Will {
|
|
|
362
362
|
|
|
363
363
|
/** Split an effectors-map entry into a handler + an EffectorDeclaration. */
|
|
364
364
|
private _register( name: string, entry: EffectorEntry ): void {
|
|
365
|
-
if( typeof entry === 'function'
|
|
365
|
+
if( typeof entry === 'function'){
|
|
366
366
|
this._effectors.set( name, entry )
|
|
367
367
|
this._effectorDecls.set( name, name ) // bare name — uniform prior
|
|
368
368
|
return
|
|
@@ -395,8 +395,8 @@ export class Will {
|
|
|
395
395
|
return {
|
|
396
396
|
tick: s.tick,
|
|
397
397
|
metrics: {
|
|
398
|
-
energy: m(
|
|
399
|
-
valence: m(
|
|
398
|
+
energy: m('energy.level', 100 ), stress: m('stress.load'), sleep: m('sleep.pressure'),
|
|
399
|
+
valence: m('affect.valence'), arousal: m('affect.arousal'),
|
|
400
400
|
},
|
|
401
401
|
goals: c.goalManager.getActiveGoals().map( g => ( { description: g.description, priority: g.priority } ) ),
|
|
402
402
|
beliefs: c.semanticIntegrator.getBeliefs().map( b => ( { statement: b.statement, confidence: b.confidence } ) ),
|
|
@@ -463,7 +463,7 @@ export class Will {
|
|
|
463
463
|
private _buildConfig( id: string, opts: CreateWillOptions ): WillConfig {
|
|
464
464
|
// Auto-detect from whichever provider key is present; explicit `llm` wins.
|
|
465
465
|
const mode = opts.llm
|
|
466
|
-
?? ( process.env.ANTHROPIC_API_KEY ? 'anthropic' : process.env.ZAI_API_KEY ? 'glm' : 'mock'
|
|
466
|
+
?? ( process.env.ANTHROPIC_API_KEY ? 'anthropic' : process.env.ZAI_API_KEY ? 'glm' : 'mock')
|
|
467
467
|
const useMock = mode === 'mock'
|
|
468
468
|
// `llm: 'glm'` selects the provider; an explicit llmConfig still overrides it.
|
|
469
469
|
const llmConfig = mode === 'glm'
|
|
@@ -581,5 +581,5 @@ export class Will {
|
|
|
581
581
|
const COMMUNICATION = [ 'listen', 'talk', 'text' ] as const
|
|
582
582
|
|
|
583
583
|
function slug( s: string ): string {
|
|
584
|
-
return s.toLowerCase().replace( /[^a-z0-9]+/g, '-'
|
|
584
|
+
return s.toLowerCase().replace( /[^a-z0-9]+/g, '-').replace( /^-+|-+$/g, '') || 'will'
|
|
585
585
|
}
|
package/src/serve/server.ts
CHANGED
|
@@ -42,7 +42,7 @@ function json( res: ServerResponse, status: number, body: unknown ): void {
|
|
|
42
42
|
async function readJsonBody( req: IncomingMessage ): Promise<Record<string, unknown>> {
|
|
43
43
|
const chunks: Buffer[] = []
|
|
44
44
|
for await ( const c of req ) chunks.push( c as Buffer )
|
|
45
|
-
const raw = Buffer.concat( chunks ).toString(
|
|
45
|
+
const raw = Buffer.concat( chunks ).toString('utf8').trim()
|
|
46
46
|
if( !raw ) return {}
|
|
47
47
|
return JSON.parse( raw ) as Record<string, unknown>
|
|
48
48
|
}
|
|
@@ -61,9 +61,9 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
|
|
|
61
61
|
const frame = `event: ${ event }\ndata: ${ JSON.stringify( data ) }\n\n`
|
|
62
62
|
for( const res of streams ) res.write( frame )
|
|
63
63
|
}
|
|
64
|
-
will.on(
|
|
65
|
-
will.on(
|
|
66
|
-
will.on(
|
|
64
|
+
will.on('message', m => fanout('utterance', m ) )
|
|
65
|
+
will.on('emotion', a => fanout('emotion', a ) )
|
|
66
|
+
will.on('effector', a => fanout('action', a ) )
|
|
67
67
|
|
|
68
68
|
const server = createServer( ( req, res ) => {
|
|
69
69
|
void handle( req, res ).catch( err => {
|
|
@@ -74,10 +74,10 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
|
|
|
74
74
|
} )
|
|
75
75
|
|
|
76
76
|
async function handle( req: IncomingMessage, res: ServerResponse ): Promise<void> {
|
|
77
|
-
const url = new URL( req.url ?? '/', 'http://sidecar'
|
|
77
|
+
const url = new URL( req.url ?? '/', 'http://sidecar')
|
|
78
78
|
const route = `${ req.method } ${ url.pathname }`
|
|
79
79
|
|
|
80
|
-
if( req.method === 'OPTIONS'
|
|
80
|
+
if( req.method === 'OPTIONS'){
|
|
81
81
|
res.writeHead( 204, {
|
|
82
82
|
'access-control-allow-origin': '*',
|
|
83
83
|
'access-control-allow-methods': 'GET, POST, OPTIONS',
|
|
@@ -109,8 +109,8 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
case 'GET /next-utterance': {
|
|
112
|
-
const within = Math.min( Math.max( parseInt( url.searchParams.get(
|
|
113
|
-
const from = url.searchParams.get(
|
|
112
|
+
const within = Math.min( Math.max( parseInt( url.searchParams.get('within_ms') ?? '15000') || 15_000, 100 ), 120_000 )
|
|
113
|
+
const from = url.searchParams.get('from') ?? undefined
|
|
114
114
|
const msg = await tap.next( within, from )
|
|
115
115
|
return msg
|
|
116
116
|
? json( res, 200, { utterance: msg } )
|
|
@@ -124,10 +124,10 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
|
|
|
124
124
|
'connection': 'keep-alive',
|
|
125
125
|
'access-control-allow-origin': '*',
|
|
126
126
|
} )
|
|
127
|
-
res.write(
|
|
127
|
+
res.write(`event: hello\ndata: ${ JSON.stringify( { name: will.name, tick: will.state().tick } ) }\n\n`)
|
|
128
128
|
streams.add( res )
|
|
129
|
-
const heartbeat = setInterval( () => res.write(
|
|
130
|
-
req.on(
|
|
129
|
+
const heartbeat = setInterval( () => res.write(`: tick ${ will.state().tick }\n\n`), SSE_HEARTBEAT_MS )
|
|
130
|
+
req.on('close', () => { clearInterval( heartbeat ); streams.delete( res ) } )
|
|
131
131
|
return
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -148,7 +148,7 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// Close open SSE streams when the server closes (so close() can complete).
|
|
151
|
-
server.on(
|
|
151
|
+
server.on('close', () => { for( const res of streams ) res.end(); streams.clear() } )
|
|
152
152
|
|
|
153
153
|
return server
|
|
154
154
|
}
|
|
@@ -36,7 +36,7 @@ export interface WiringRecord {
|
|
|
36
36
|
|
|
37
37
|
/** `attachFooBar` → `_fooBar` (the codebase-wide injector/field convention). */
|
|
38
38
|
function fieldForAttach( method: string ): string {
|
|
39
|
-
const stem = method.slice(
|
|
39
|
+
const stem = method.slice('attach'.length )
|
|
40
40
|
return '_' + stem.charAt( 0 ).toLowerCase() + stem.slice( 1 )
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -46,7 +46,7 @@ function attachMethods( engine: object ): string[] {
|
|
|
46
46
|
let proto: object | null = engine
|
|
47
47
|
while( proto && proto !== Object.prototype ){
|
|
48
48
|
for( const name of Object.getOwnPropertyNames( proto ) )
|
|
49
|
-
if( /^attach[A-Z]/.test( name ) && typeof ( engine as Record<string, unknown> )[ name ] === 'function'
|
|
49
|
+
if( /^attach[A-Z]/.test( name ) && typeof ( engine as Record<string, unknown> )[ name ] === 'function')
|
|
50
50
|
seen.add( name )
|
|
51
51
|
proto = Object.getPrototypeOf( proto )
|
|
52
52
|
}
|
|
@@ -84,5 +84,5 @@ export function auditAssemblyWiring( engines: readonly SimulationEngine[] ): Wir
|
|
|
84
84
|
|
|
85
85
|
/** Compact `engine.attachMethod` keys for the given status (test snapshots). */
|
|
86
86
|
export function wiringKeys( records: WiringRecord[], status: WiringRecord['status'] ): string[] {
|
|
87
|
-
return records.filter( r => r.status === status ).map( r => `${r.engine}.${r.method}`
|
|
87
|
+
return records.filter( r => r.status === status ).map( r => `${r.engine}.${r.method}`).sort()
|
|
88
88
|
}
|
|
@@ -81,12 +81,12 @@ An empty "issues" array means the persona is fine.`
|
|
|
81
81
|
export function buildCoherenceUserMessage( input: CoherenceInput ): string {
|
|
82
82
|
const id = input.identity
|
|
83
83
|
const parts = [
|
|
84
|
-
`PERSONA PROMPT:\n${( id.prompt ?? ''
|
|
85
|
-
`VALUES: ${( id.values ?? [] ).join(
|
|
86
|
-
`STYLE: ${( id.style ?? ''
|
|
84
|
+
`PERSONA PROMPT:\n${( id.prompt ?? '').trim() || '(empty)'}`,
|
|
85
|
+
`VALUES: ${( id.values ?? [] ).join(', ') || '(none)'}`,
|
|
86
|
+
`STYLE: ${( id.style ?? '').trim() || '(none)'}`,
|
|
87
87
|
]
|
|
88
|
-
if( input.profileContext ) parts.push(
|
|
89
|
-
return parts.join(
|
|
88
|
+
if( input.profileContext ) parts.push(`PROFILE CONTEXT:\n${input.profileContext.trim()}`)
|
|
89
|
+
return parts.join('\n\n')
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
export async function checkIdentityCoherence(
|
|
@@ -104,7 +104,7 @@ export async function checkIdentityCoherence(
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
const issues = parseIssues( text )
|
|
107
|
-
return { ok: !issues.some( i => i.severity === 'error'
|
|
107
|
+
return { ok: !issues.some( i => i.severity === 'error'), ran: true, issues, raw: text }
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/** Convenience: build a provider client from env and run the review. */
|
|
@@ -112,7 +112,7 @@ export async function reviewIdentityCoherence(
|
|
|
112
112
|
input: CoherenceInput,
|
|
113
113
|
opts: { willId?: string; tokenTracker?: TokenTracker | null } = {},
|
|
114
114
|
): Promise<CoherenceResult> {
|
|
115
|
-
const provider = ( process.env.WILL_LLM_PROVIDER ?? 'anthropic'
|
|
115
|
+
const provider = ( process.env.WILL_LLM_PROVIDER ?? 'anthropic') as LLMProvider
|
|
116
116
|
const director = new LLMDirector({
|
|
117
117
|
willId: opts.willId ?? 'identity-coherence',
|
|
118
118
|
model: process.env.WILL_LLM_MODEL ?? defaultModelFor( provider ),
|
|
@@ -131,8 +131,8 @@ export async function reviewIdentityCoherence(
|
|
|
131
131
|
// ── parsing ────────────────────────────────────────────────────
|
|
132
132
|
|
|
133
133
|
function parseIssues( text: string ): CoherenceIssue[] {
|
|
134
|
-
const start = text.indexOf(
|
|
135
|
-
const end = text.lastIndexOf(
|
|
134
|
+
const start = text.indexOf('{')
|
|
135
|
+
const end = text.lastIndexOf('}')
|
|
136
136
|
if( start < 0 || end <= start ) return []
|
|
137
137
|
|
|
138
138
|
let obj: { issues?: unknown }
|
|
@@ -143,7 +143,7 @@ function parseIssues( text: string ): CoherenceIssue[] {
|
|
|
143
143
|
|
|
144
144
|
const out: CoherenceIssue[] = []
|
|
145
145
|
for( const raw of obj.issues ){
|
|
146
|
-
if( !raw || typeof raw !== 'object'
|
|
146
|
+
if( !raw || typeof raw !== 'object') continue
|
|
147
147
|
const r = raw as Record<string, unknown>
|
|
148
148
|
const detail = typeof r['detail'] === 'string' ? r['detail'] : ''
|
|
149
149
|
if( !detail ) continue
|
|
@@ -110,11 +110,11 @@ const CAPABILITY_CLAIM_PATTERNS: Array<[ RegExp, string ]> = [
|
|
|
110
110
|
/** Strip markdown header lines that forge a section the executive prompt owns. */
|
|
111
111
|
function stripReservedHeaders( text: string ): { text: string; stripped: boolean } {
|
|
112
112
|
let stripped = false
|
|
113
|
-
const out = text.split(
|
|
113
|
+
const out = text.split('\n').filter( line => {
|
|
114
114
|
const m = /^\s*#{1,6}\s*(.+?)\s*$/.exec( line )
|
|
115
115
|
if( m && RESERVED_SECTIONS.has( m[1]!.toLowerCase() ) ){ stripped = true; return false }
|
|
116
116
|
return true
|
|
117
|
-
} ).join(
|
|
117
|
+
} ).join('\n')
|
|
118
118
|
return { text: out, stripped }
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -125,59 +125,59 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
|
|
|
125
125
|
const id: WillIdentity = input.identity ?? { prompt: '', values: [], traits: {}, style: '' }
|
|
126
126
|
|
|
127
127
|
// ── prompt: hijack strip → length → injection ────────────────
|
|
128
|
-
let prompt = ( id.prompt ?? ''
|
|
128
|
+
let prompt = ( id.prompt ?? '').trim()
|
|
129
129
|
const hdr = stripReservedHeaders( prompt )
|
|
130
130
|
if( hdr.stripped ){
|
|
131
131
|
prompt = hdr.text.trim()
|
|
132
|
-
warnings.push(
|
|
132
|
+
warnings.push('identity.prompt forged reserved section headers (## Personality / ## Output Guidelines / …); stripped to protect prompt structure.')
|
|
133
133
|
}
|
|
134
134
|
if( prompt.length > MAX_PROMPT_CHARS )
|
|
135
|
-
errors.push(
|
|
135
|
+
errors.push(`identity.prompt is ${prompt.length} chars (max ${MAX_PROMPT_CHARS}) — it would dilute the core grounding and inflate cost.`)
|
|
136
136
|
const promptEmpty = prompt.length === 0
|
|
137
137
|
if( !promptEmpty && prompt.length < MIN_PROMPT_CHARS )
|
|
138
|
-
warnings.push(
|
|
138
|
+
warnings.push(`identity.prompt is very short (${prompt.length} chars) — a thin persona behaves generically.`)
|
|
139
139
|
if( INJECTION_PATTERNS.some( re => re.test( prompt ) ) )
|
|
140
|
-
warnings.push(
|
|
140
|
+
warnings.push('identity.prompt contains an instruction-injection pattern — it may fight the core grounding; review before deploying.')
|
|
141
141
|
|
|
142
142
|
const claimedSenses = new Set<string>()
|
|
143
143
|
for( const [ re, sense ] of CAPABILITY_CLAIM_PATTERNS )
|
|
144
144
|
if( re.test( prompt ) ) claimedSenses.add( sense )
|
|
145
145
|
if( claimedSenses.size )
|
|
146
|
-
warnings.push(
|
|
146
|
+
warnings.push(`identity.prompt claims capabilities the Will lacks (${[ ...claimedSenses ].join(', ')}) — it perceives through text/conversation and may hallucinate using them.`)
|
|
147
147
|
|
|
148
148
|
// ── values ───────────────────────────────────────────────────
|
|
149
149
|
let values = Array.from( new Set( ( id.values ?? [] ).map( v => String( v ).trim() ).filter( Boolean ) ) )
|
|
150
150
|
if( values.length > MAX_VALUES ){
|
|
151
|
-
warnings.push(
|
|
151
|
+
warnings.push(`identity.values has more than ${MAX_VALUES} entries; truncated.`)
|
|
152
152
|
values = values.slice( 0, MAX_VALUES )
|
|
153
153
|
}
|
|
154
154
|
const valuesEmpty = values.length === 0
|
|
155
|
-
if( valuesEmpty ) warnings.push(
|
|
155
|
+
if( valuesEmpty ) warnings.push('identity.values is empty — values ground the Will’s decisions; consider seeding a few.')
|
|
156
156
|
|
|
157
157
|
// ── traits: finite → range → vocabulary ──────────────────────
|
|
158
158
|
const traits: Record<string, number> = {}
|
|
159
159
|
for( const [ rawKey, rawVal ] of Object.entries( id.traits ?? {} ) ){
|
|
160
160
|
const key = rawKey.trim()
|
|
161
161
|
const val = Number( rawVal )
|
|
162
|
-
if( !Number.isFinite( val ) ){ errors.push(
|
|
162
|
+
if( !Number.isFinite( val ) ){ errors.push(`trait "${key}" is not a finite number (${String( rawVal )}).`); continue }
|
|
163
163
|
let clamped = val
|
|
164
164
|
if( val < 0 || val > 1 ){
|
|
165
165
|
clamped = val < 0 ? 0 : 1
|
|
166
|
-
warnings.push(
|
|
166
|
+
warnings.push(`trait "${key}" = ${val} is outside [0,1]; clamped to ${clamped}.`)
|
|
167
167
|
}
|
|
168
168
|
if( !KNOWN_TRAITS.has( key.toLowerCase() ) )
|
|
169
|
-
warnings.push(
|
|
169
|
+
warnings.push(`trait "${key}" is not a recognised trait — it may be ignored by the persona layer.`)
|
|
170
170
|
traits[ key ] = clamped
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
// ── style ─────────────────────────────────────────────────────
|
|
174
|
-
let style = ( id.style ?? ''
|
|
174
|
+
let style = ( id.style ?? '').trim()
|
|
175
175
|
if( style.length > MAX_STYLE_CHARS ){
|
|
176
|
-
warnings.push(
|
|
176
|
+
warnings.push('identity.style is long; it reads better as a short phrase.')
|
|
177
177
|
style = style.slice( 0, MAX_STYLE_CHARS )
|
|
178
178
|
}
|
|
179
179
|
if( GENERIC_STYLES.has( style.toLowerCase() ) )
|
|
180
|
-
warnings.push(
|
|
180
|
+
warnings.push('identity.style is generic — a distinct voice prevents collapse into a generic chatbot tone.')
|
|
181
181
|
|
|
182
182
|
// ── effectors: collisions ─────────────────────────────────────
|
|
183
183
|
let effectors = input.effectors ?? null
|
|
@@ -187,7 +187,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
|
|
|
187
187
|
for( const a of effectors ){
|
|
188
188
|
const name = String( a ).trim()
|
|
189
189
|
if( !name ) continue
|
|
190
|
-
if( seen.has( name ) ){ warnings.push(
|
|
190
|
+
if( seen.has( name ) ){ warnings.push(`duplicate effector "${name}" removed.`); continue }
|
|
191
191
|
seen.add( name )
|
|
192
192
|
// A custom (non-comms) effector that shadows an innate stance is un-enactable as
|
|
193
193
|
// a host effector — the innate floor already provides it. Drop it with a warning
|
|
@@ -195,7 +195,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
|
|
|
195
195
|
// list innate stances like `remember`/`reflect`, and the external-schema
|
|
196
196
|
// synthesizer already skips them (see agency/schemas/external.ts).
|
|
197
197
|
if( !EXPLICIT_EFFECTORS.has( name ) && INNATE_SCHEMA_BY_ID.has( name ) ){
|
|
198
|
-
warnings.push(
|
|
198
|
+
warnings.push(`effector "${name}" shadows an innate stance — it's provided innately and won't be enacted as a host effector.`)
|
|
199
199
|
continue
|
|
200
200
|
}
|
|
201
201
|
out.push( name )
|
|
@@ -205,12 +205,12 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
|
|
|
205
205
|
|
|
206
206
|
// ── profile context ──────────────────────────────────────────
|
|
207
207
|
let profileContext = input.profileContext
|
|
208
|
-
if( typeof profileContext === 'string'
|
|
208
|
+
if( typeof profileContext === 'string'){
|
|
209
209
|
const c = stripReservedHeaders( profileContext )
|
|
210
|
-
if( c.stripped ) warnings.push(
|
|
210
|
+
if( c.stripped ) warnings.push('profile context forged reserved section headers; stripped.')
|
|
211
211
|
profileContext = c.text.trim()
|
|
212
212
|
if( profileContext.length > MAX_CONTEXT_CHARS )
|
|
213
|
-
errors.push(
|
|
213
|
+
errors.push(`profile context is ${profileContext.length} chars (max ${MAX_CONTEXT_CHARS}).`)
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// ── identity strength (collapse signal) ──────────────────────
|
|
@@ -222,7 +222,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
|
|
|
222
222
|
+ 0.15 * ( Object.keys( traits ).length > 0 ? 1 : 0 )
|
|
223
223
|
) * 100 ) / 100
|
|
224
224
|
if( identityStrength < 0.4 )
|
|
225
|
-
warnings.push(
|
|
225
|
+
warnings.push(`identity is shallow (strength ${identityStrength}) — the Will behaves generically until it develops one.`)
|
|
226
226
|
|
|
227
227
|
return {
|
|
228
228
|
ok: errors.length === 0,
|
package/src/stem/index.ts
CHANGED
|
@@ -225,10 +225,10 @@ export class WillStem {
|
|
|
225
225
|
const previousState = await simulation.snapshotManager.loadLatestFromStorage()
|
|
226
226
|
if( previousState ){
|
|
227
227
|
simulation.stateManager.restore( previousState, { entities: true, metrics: false } )
|
|
228
|
-
logger.info(
|
|
228
|
+
logger.info(`[WillStem] Restored snapshot for ${config.id} — ${previousState.entities.size} entities loaded`)
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
catch( err ){ logger.warn(
|
|
231
|
+
catch( err ){ logger.warn(`[WillStem] Snapshot restore failed for ${config.id} — starting fresh:`, err ) }
|
|
232
232
|
|
|
233
233
|
const
|
|
234
234
|
dataDir = process.env.WILL_DATA_DIR ?? './data',
|
|
@@ -310,7 +310,7 @@ export class WillStem {
|
|
|
310
310
|
// Buffer host-owned effector invocations for delivery. The MotorSchemaExecutor
|
|
311
311
|
// emits `agency.invocation` (intentId = correlation handle) when it holds an
|
|
312
312
|
// external action 'awaiting'; the host executes it and acks → confirmExecution.
|
|
313
|
-
if( event.type === 'agency.invocation'
|
|
313
|
+
if( event.type === 'agency.invocation')
|
|
314
314
|
this._effector.bufferInvocation( instance, event.payload as Record<string, unknown> )
|
|
315
315
|
|
|
316
316
|
if( instance.simulationEventListeners.size === 0 ) return
|
|
@@ -457,7 +457,7 @@ export class WillStem {
|
|
|
457
457
|
instance.simulation.stateManager.applyCommands( flushCmds )
|
|
458
458
|
const pauseState = instance.simulation.stateManager.snapshot()
|
|
459
459
|
instance.simulation.snapshotManager.persistNow( pauseState )
|
|
460
|
-
.catch( err => logger.error(
|
|
460
|
+
.catch( err => logger.error(`[WillStem] snapshot persist failed on pause (${id}):`, err ))
|
|
461
461
|
|
|
462
462
|
this._biography.writeSessionSummary( instance )
|
|
463
463
|
this._biography.writeEmotionalBiographySummary( instance )
|
|
@@ -807,6 +807,16 @@ export class WillStem {
|
|
|
807
807
|
this._effector.confirmExecution( this._get( id ), invocationId, result )
|
|
808
808
|
}
|
|
809
809
|
|
|
810
|
+
/**
|
|
811
|
+
* Resolve a policy escalation the Will raised (POLICY_REAFFERENCE P4).
|
|
812
|
+
* `approved` dispatches the held invocation to the world; otherwise it is
|
|
813
|
+
* refused. Applied at the next tick boundary. `invocationId` is the awaiting
|
|
814
|
+
* `agency.intent` id the escalation ask referenced.
|
|
815
|
+
*/
|
|
816
|
+
resolveEscalation( id: string, invocationId: string, approved: boolean ): void {
|
|
817
|
+
this._effector.resolveEscalation( this._get( id ), invocationId, approved )
|
|
818
|
+
}
|
|
819
|
+
|
|
810
820
|
// ── Messaging / outbox (11.1) ────────────────────────────────────────────
|
|
811
821
|
// Delegates to OutboxController (R5-c). `_get(id)` validates the Will exists
|
|
812
822
|
// and supplies the WillInstance; the outbox ops touch only instance fields.
|
|
@@ -963,6 +973,11 @@ export class WillStem {
|
|
|
963
973
|
sensory: this._sensory,
|
|
964
974
|
} )
|
|
965
975
|
|
|
976
|
+
// Apply policy refusals queued during the previous step's flush, at the
|
|
977
|
+
// same boundary and for the same reason (POLICY_REAFFERENCE P1): a denial
|
|
978
|
+
// reconciles as a host-rejection-shaped failure ack the step then sees.
|
|
979
|
+
this._effector.applyPolicyOutcomes( instance )
|
|
980
|
+
|
|
966
981
|
await instance.simulation.step( 1 )
|
|
967
982
|
|
|
968
983
|
instance.tickCount++
|
|
@@ -1029,9 +1044,9 @@ export class WillStem {
|
|
|
1029
1044
|
// executive confidence, goal outcomes, and significant emotional events.
|
|
1030
1045
|
if( instance._sessionBehavior ){
|
|
1031
1046
|
const sb = instance._sessionBehavior
|
|
1032
|
-
const v = snapshot.metrics.get(
|
|
1033
|
-
const a = snapshot.metrics.get(
|
|
1034
|
-
const c = snapshot.metrics.get(
|
|
1047
|
+
const v = snapshot.metrics.get('affect.valence') ?? 0
|
|
1048
|
+
const a = snapshot.metrics.get('affect.arousal') ?? 0
|
|
1049
|
+
const c = snapshot.metrics.get('executive.confidence')
|
|
1035
1050
|
|
|
1036
1051
|
// ── Range tracking ──────────────────────────────────────
|
|
1037
1052
|
if( v < sb.valenceMin ) sb.valenceMin = v
|
|
@@ -1039,8 +1054,8 @@ export class WillStem {
|
|
|
1039
1054
|
if( a < sb.arousalMin ) sb.arousalMin = a
|
|
1040
1055
|
if( a > sb.arousalMax ) sb.arousalMax = a
|
|
1041
1056
|
if( c !== undefined ){ sb.confidenceSum += c; sb.confidenceCount++ }
|
|
1042
|
-
const gt = snapshot.metrics.get(
|
|
1043
|
-
const gc = snapshot.metrics.get(
|
|
1057
|
+
const gt = snapshot.metrics.get('goals.total')
|
|
1058
|
+
const gc = snapshot.metrics.get('goals.completed_total')
|
|
1044
1059
|
if( gt !== undefined ) sb.goalsTotal = gt
|
|
1045
1060
|
if( gc !== undefined ) sb.goalsCompleted = gc
|
|
1046
1061
|
|
|
@@ -1101,8 +1116,8 @@ export class WillStem {
|
|
|
1101
1116
|
sb.prevArousal = a
|
|
1102
1117
|
|
|
1103
1118
|
// Track impulsive actions: ticks where executive fired with low confidence
|
|
1104
|
-
const conf = snapshot.metrics.get(
|
|
1105
|
-
const actCount = Math.round( snapshot.metrics.get(
|
|
1119
|
+
const conf = snapshot.metrics.get('executive.confidence')
|
|
1120
|
+
const actCount = Math.round( snapshot.metrics.get('executive.action_count') ?? 0 )
|
|
1106
1121
|
if( conf !== undefined && conf < 0.35 && actCount > 0 )
|
|
1107
1122
|
sb.impulsiveActionCount += actCount
|
|
1108
1123
|
}
|