@mindot/will 0.4.0 → 0.6.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.
Files changed (135) hide show
  1. package/README.md +32 -12
  2. package/dist/channels/discord.d.ts +2 -11
  3. package/dist/channels/discord.js.map +1 -1
  4. package/dist/channels/whatsapp.d.ts +72 -0
  5. package/dist/channels/whatsapp.js +252 -0
  6. package/dist/channels/whatsapp.js.map +1 -0
  7. package/dist/cli.js +837 -91
  8. package/dist/cli.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +620 -79
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp/effectors.d.ts +1 -1
  13. package/dist/mcp/effectors.js.map +1 -1
  14. package/dist/types-E9-HV-SW.d.ts +11 -0
  15. package/dist/{will-D-slky1N.d.ts → will-Bikuk4s2.d.ts} +56 -12
  16. package/package.json +12 -3
  17. package/src/channels/discord.ts +11 -11
  18. package/src/channels/roster.ts +1 -1
  19. package/src/channels/types.ts +1 -1
  20. package/src/channels/whatsapp.ts +318 -0
  21. package/src/cli.ts +46 -23
  22. package/src/cognition/acp.ts +28 -0
  23. package/src/cognition/agency/consequence.ts +174 -0
  24. package/src/cognition/agency/engines/action.selector.ts +301 -48
  25. package/src/cognition/agency/engines/affordance.synthesizer.ts +26 -16
  26. package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
  27. package/src/cognition/agency/engines/motor.schema.executor.ts +86 -14
  28. package/src/cognition/agency/engines/reafference.engine.ts +122 -18
  29. package/src/cognition/agency/execution.primitives.ts +13 -13
  30. package/src/cognition/agency/proactive.communicator.ts +1 -1
  31. package/src/cognition/agency/reconcile.learning.ts +1 -1
  32. package/src/cognition/agency/revocation.ts +79 -0
  33. package/src/cognition/agency/schemas/repertoire.ts +2 -2
  34. package/src/cognition/agency/selection.scoring.ts +25 -9
  35. package/src/cognition/bus.ts +2 -2
  36. package/src/cognition/completion.inbox.ts +1 -1
  37. package/src/cognition/config.mirror.entities.ts +5 -5
  38. package/src/cognition/event.log.ts +2 -2
  39. package/src/cognition/event.schemas.ts +67 -67
  40. package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
  41. package/src/cognition/faculties/affective.blender.ts +36 -4
  42. package/src/cognition/faculties/attachment.evaluator.ts +6 -6
  43. package/src/cognition/faculties/attention.allocator.ts +63 -8
  44. package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
  45. package/src/cognition/faculties/bias.detector.ts +7 -7
  46. package/src/cognition/faculties/circadian.oscillator.ts +3 -3
  47. package/src/cognition/faculties/confidence.calibrator.ts +7 -7
  48. package/src/cognition/faculties/dream.simulator.ts +5 -5
  49. package/src/cognition/faculties/empathy.simulator.ts +7 -7
  50. package/src/cognition/faculties/energy.regulator.ts +4 -4
  51. package/src/cognition/faculties/episodic.consolidator.ts +6 -6
  52. package/src/cognition/faculties/executive.engine/commands.ts +6 -6
  53. package/src/cognition/faculties/executive.engine/context.ts +42 -42
  54. package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
  55. package/src/cognition/faculties/executive.engine/engine.ts +27 -26
  56. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
  57. package/src/cognition/faculties/executive.engine/facet.ts +18 -18
  58. package/src/cognition/faculties/executive.engine/gating.ts +2 -2
  59. package/src/cognition/faculties/executive.engine/messages.ts +3 -3
  60. package/src/cognition/faculties/executive.engine/parser.ts +11 -11
  61. package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
  62. package/src/cognition/faculties/exteroception.ts +99 -5
  63. package/src/cognition/faculties/forgetting.curve.ts +3 -3
  64. package/src/cognition/faculties/frustration.evaluator.ts +6 -6
  65. package/src/cognition/faculties/goal.manager.ts +15 -15
  66. package/src/cognition/faculties/inhibition.controller.ts +3 -3
  67. package/src/cognition/faculties/interoception.ts +3 -3
  68. package/src/cognition/faculties/introspection.engine.ts +3 -3
  69. package/src/cognition/faculties/known.entity.tracker.ts +15 -15
  70. package/src/cognition/faculties/loss.evaluator.ts +2 -2
  71. package/src/cognition/faculties/moral.evaluator.ts +4 -4
  72. package/src/cognition/faculties/novelty.detector.ts +4 -4
  73. package/src/cognition/faculties/persona.consolidator.ts +12 -12
  74. package/src/cognition/faculties/planning.engine/engine.ts +47 -47
  75. package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
  76. package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
  77. package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
  78. package/src/cognition/faculties/reputation.tracker.ts +6 -6
  79. package/src/cognition/faculties/reward.evaluator.ts +4 -4
  80. package/src/cognition/faculties/self.model.updater.ts +8 -8
  81. package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
  82. package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
  83. package/src/cognition/faculties/social.perception.ts +3 -3
  84. package/src/cognition/faculties/spaced.repetition.ts +2 -2
  85. package/src/cognition/faculties/stress.regulator.ts +27 -4
  86. package/src/cognition/faculties/task.switcher.ts +11 -6
  87. package/src/cognition/faculties/theory.of.mind.ts +6 -6
  88. package/src/cognition/faculties/threat.evaluator.ts +3 -3
  89. package/src/cognition/faculties/working.memory.ts +8 -8
  90. package/src/cognition/generative.model.ts +2 -2
  91. package/src/cognition/memory/vector.adapter.ts +5 -5
  92. package/src/cognition/memory/vector.content.ts +4 -4
  93. package/src/cognition/memory/vector.embedder.ts +9 -9
  94. package/src/cognition/persona.prior.ts +1 -1
  95. package/src/cognition/schema.registry.ts +2 -2
  96. package/src/cognition/senses/audition.engine/engine.ts +2 -2
  97. package/src/cognition/senses/base.sense.engine.ts +1 -1
  98. package/src/cognition/utilities/token.tracker.ts +11 -5
  99. package/src/core/abstracts.ts +1 -1
  100. package/src/core/completion.recorder.ts +2 -2
  101. package/src/core/serialization.ts +3 -3
  102. package/src/core/snapshot.manager.ts +1 -1
  103. package/src/core/state.manager.ts +1 -1
  104. package/src/core/utils.ts +1 -1
  105. package/src/host/boot.ts +59 -37
  106. package/src/host/utterances.ts +1 -1
  107. package/src/llm/index.ts +84 -34
  108. package/src/llm/summarizer.ts +4 -4
  109. package/src/llm/wire.contracts.ts +1 -1
  110. package/src/mcp/effectors.ts +10 -10
  111. package/src/mcp/server.ts +11 -11
  112. package/src/pma/eval.ts +1 -1
  113. package/src/pma/index.ts +21 -21
  114. package/src/runners/outreach.runner.ts +3 -3
  115. package/src/runners/social.runner.ts +1 -1
  116. package/src/runners/thin-shim.runner.ts +1 -1
  117. package/src/sdk/will.ts +20 -11
  118. package/src/serve/server.ts +12 -12
  119. package/src/stem/assembly.audit.ts +3 -3
  120. package/src/stem/guards/identity.coherence.ts +13 -12
  121. package/src/stem/guards/identity.guard.ts +22 -22
  122. package/src/stem/index.ts +11 -11
  123. package/src/stem/mind.ts +12 -12
  124. package/src/stem/tracts/biography.writer.ts +3 -3
  125. package/src/stem/tracts/effector.controller.ts +4 -4
  126. package/src/stem/tracts/health.reporter.ts +1 -1
  127. package/src/stem/tracts/outbox.controller.ts +4 -0
  128. package/src/stem/tracts/outbox.writer.ts +4 -4
  129. package/src/stem/tracts/pma.controller.ts +1 -1
  130. package/src/stem/tracts/replay.controller.ts +10 -10
  131. package/src/stem/tracts/sensory.controller.ts +2 -2
  132. package/src/stem/tracts/session.logger.ts +4 -4
  133. package/src/stem/tracts/transport/socketio.transport.ts +7 -7
  134. package/src/stem/tracts/transport/stream.transport.ts +2 -2
  135. package/src/stem/tracts/transport.controller.ts +15 -15
@@ -103,7 +103,7 @@ export async function buildExecutiveContext(
103
103
  }
104
104
 
105
105
  // Filter goal-type episodes — they duplicate the Active Goals section
106
- const recalled = combined.filter( ep => ep.sourceType !== 'goal' ).slice( 0, 8 )
106
+ const recalled = combined.filter( ep => ep.sourceType !== 'goal').slice( 0, 8 )
107
107
  relevantPlanIds = collectPlanIds( recalled )
108
108
  memories = recalled.map( mapEpisodeToMemory )
109
109
  // Recall reinforces retention: marking each surfaced episode as retrieved
@@ -117,7 +117,7 @@ export async function buildExecutiveContext(
117
117
  // the default query order may not be chronological when using PMA replay.
118
118
  const fallbackResults = deps.episodicConsolidator.query({ limit: 20 })
119
119
  const recalled = fallbackResults
120
- .filter( ep => ep.sourceType !== 'goal' )
120
+ .filter( ep => ep.sourceType !== 'goal')
121
121
  .slice()
122
122
  .sort( ( a, b ) => ( ( b.createdAt as unknown as number ) ?? 0 ) - ( ( a.createdAt as unknown as number ) ?? 0 ) )
123
123
  .slice( 0, 8 )
@@ -168,7 +168,7 @@ export async function buildExecutiveContext(
168
168
 
169
169
  // ── Stage 1: Deduplication ────────────────────────────────
170
170
  const _tokenize = ( s: string ): Set<string> =>
171
- new Set( s.toLowerCase().replace( /[^a-z0-9 ]/g, '' ).split( /\s+/ ).filter( Boolean ) )
171
+ new Set( s.toLowerCase().replace( /[^a-z0-9 ]/g, '').split( /\s+/ ).filter( Boolean ) )
172
172
 
173
173
  const _jaccard = ( a: Set<string>, b: Set<string> ): number => {
174
174
  let intersection = 0
@@ -236,7 +236,7 @@ export async function buildExecutiveContext(
236
236
  // impulsivity falls as conscientiousness is demonstrated. So it is no longer static
237
237
  // per session. `readEffectiveParams` only layers a prior onto a key the base already
238
238
  // has, so absent a PMA seed this degrades to base ⇒ undefined disposition.
239
- const execParams = readEffectiveParams( state, 'engine-config-executive' )
239
+ const execParams = readEffectiveParams( state, 'engine-config-executive')
240
240
  const behavioralDisposition = (
241
241
  execParams.riskTolerance !== undefined ||
242
242
  execParams.explorationRate !== undefined ||
@@ -257,7 +257,7 @@ export async function buildExecutiveContext(
257
257
  }> = []
258
258
 
259
259
  for( const entity of state.entities.values() ){
260
- if( entity.type !== 'decision.record' ) continue
260
+ if( entity.type !== 'decision.record') continue
261
261
  const actionStatus = entity.metadata?.actionStatus as string | undefined
262
262
  if( !actionStatus ) continue
263
263
  if( !( [ 'completed', 'failed', 'awaiting_host', 'timed_out' ] as string[] ).includes( actionStatus ) ) continue
@@ -266,7 +266,7 @@ export async function buildExecutiveContext(
266
266
  type: ( entity.metadata?.actionType as string ) ?? 'unknown',
267
267
  status: actionStatus as 'completed' | 'failed' | 'awaiting_host' | 'timed_out',
268
268
  tick: ( entity.metadata?.executionTick as number ) ?? ( entity.metadata?.dispatchedAt as number ) ?? 0,
269
- outcome: String( entity.metadata?.outcome ?? '' ).slice( 0, 120 ),
269
+ outcome: String( entity.metadata?.outcome ?? '').slice( 0, 120 ),
270
270
  planId: entity.metadata?.planId as string | undefined,
271
271
  })
272
272
  }
@@ -280,7 +280,7 @@ export async function buildExecutiveContext(
280
280
  // progress, enabling it to target a specific plan by id when managing several. (P4)
281
281
  const plans: ExecutiveContext['plans'] = []
282
282
  for( const entity of state.entities.values() ){
283
- if( entity.type !== 'plan' ) continue
283
+ if( entity.type !== 'plan') continue
284
284
  const m = entity.metadata ?? {}
285
285
  const steps = ( m['steps'] as Array<{ status?: string }> | undefined ) ?? []
286
286
  plans.push({
@@ -289,7 +289,7 @@ export async function buildExecutiveContext(
289
289
  status: ( m['status'] as string ) ?? 'unknown',
290
290
  executionTier: ( m['executionTier'] as string ) ?? 'automatic',
291
291
  totalSteps: steps.length,
292
- completedSteps: steps.filter( s => s.status === 'completed' || s.status === 'skipped' ).length,
292
+ completedSteps: steps.filter( s => s.status === 'completed' || s.status === 'skipped').length,
293
293
  expectedOutcome: ( m['expectedOutcome'] as string ) ?? '',
294
294
  requestingEntityId: m['requestingEntityId'] as string | undefined,
295
295
  })
@@ -346,7 +346,7 @@ const MAX_SURFACED_ABILITIES = 8
346
346
  export function extractAbilities( state: ReadonlySimulationState ): ExecutiveContext['abilities'] {
347
347
  const out: NonNullable<ExecutiveContext['abilities']> = []
348
348
  for( const e of state.entities.values() ){
349
- if( e.type !== 'affordance' ) continue
349
+ if( e.type !== 'affordance') continue
350
350
  const m = e.metadata as Record<string, unknown> | undefined
351
351
  if( m?.['source'] !== 'external' || m?.['available'] === false ) continue
352
352
  const name = typeof m?.['schema'] === 'string' ? m['schema'] as string : undefined
@@ -372,13 +372,13 @@ export function extractCurrentFocus(
372
372
  state: ReadonlySimulationState,
373
373
  goals: ExecutiveContext['goals']
374
374
  ): ExecutiveContext['currentFocus'] {
375
- const m = state.entities.get( 'task-switch-focus' )?.metadata as Record<string, unknown> | undefined
375
+ const m = state.entities.get('task-switch-focus')?.metadata as Record<string, unknown> | undefined
376
376
  if( !m?.goalId ) return undefined
377
377
  return {
378
378
  goalId: m.goalId as string,
379
379
  goalDescription: goals.find( g => g.id === m.goalId )?.description,
380
380
  focusTicks: ( m.focusTicks as number ) ?? 0,
381
- switchCost: state.metrics.get( 'task_switch.switch_cost' ) ?? 0,
381
+ switchCost: state.metrics.get('task_switch.switch_cost') ?? 0,
382
382
  }
383
383
  }
384
384
 
@@ -397,7 +397,7 @@ export function extractKnownEntities( state: ReadonlySimulationState ): Executiv
397
397
  // triple / dossier / beliefs under the old keid all aggregate under the one someone.
398
398
  const alias = new Map<string, string>()
399
399
  for( const e of state.entities.values() )
400
- if( e.type === 'known-entity-alias' ){
400
+ if( e.type === 'known-entity-alias'){
401
401
  const a = e.metadata?.aliasKeid as string | undefined
402
402
  const c = e.metadata?.canonicalKeid as string | undefined
403
403
  if( a && c ) alias.set( a, c )
@@ -421,7 +421,7 @@ export function extractKnownEntities( state: ReadonlySimulationState ): Executiv
421
421
  }
422
422
  else if( e.type === 'reputation' && m.keid ){
423
423
  const a = get( m.keid as string )
424
- if( typeof m.name === 'string' ) a.name = m.name
424
+ if( typeof m.name === 'string') a.name = m.name
425
425
  a.trust = m.trustworthiness as number
426
426
  a.cooperativeness = m.cooperativeness as number
427
427
  a.reliability ??= m.reliability as number // sentient social reliability — the dossier's wins if present
@@ -433,13 +433,13 @@ export function extractKnownEntities( state: ReadonlySimulationState ): Executiv
433
433
  // sentient social one). (familiarity is intentionally NOT surfaced — it decays each
434
434
  // tick and would churn the cached prompt; it stays internal to the tracker.)
435
435
  const a = get( m.keid as string )
436
- if( typeof m.name === 'string' ) a.name = m.name
437
- if( m.kind === 'thing' || m.kind === 'sentient' ) a.kind = m.kind as 'thing' | 'sentient'
438
- if( typeof m.reliability === 'number' ) a.reliability = m.reliability as number
436
+ if( typeof m.name === 'string') a.name = m.name
437
+ if( m.kind === 'thing' || m.kind === 'sentient') a.kind = m.kind as 'thing' | 'sentient'
438
+ if( typeof m.reliability === 'number') a.reliability = m.reliability as number
439
439
  a._recency = Math.max( a._recency, ( m.lastSeenTick as number ) ?? 0 )
440
440
  }
441
- else if( e.type === 'attachment.bond' ){
442
- const keid = ( m.keid as string ) ?? e.id.replace( /^bond-/, '' )
441
+ else if( e.type === 'attachment.bond'){
442
+ const keid = ( m.keid as string ) ?? e.id.replace( /^bond-/, '')
443
443
  get( keid ).closeness = m.attachmentStrength as number
444
444
  }
445
445
  }
@@ -465,33 +465,33 @@ function buildSemanticQuery(
465
465
  // Active goals (highest priority first)
466
466
  const goals = goalManager?.getActiveGoals().slice( 0, 3 ) ?? []
467
467
  if( goals.length > 0 ){
468
- parts.push( `Current goals: ${goals.map( g => g.description ).join( '; ' )}` )
468
+ parts.push(`Current goals: ${goals.map( g => g.description ).join('; ')}`)
469
469
  }
470
470
 
471
471
  // Dominant emotion if intense
472
472
  const valence = state.metrics.get('affect.valence') ?? 0
473
473
  const dominantEmotion = valence > 0.3 ? 'positive' : valence < -0.3 ? 'negative' : 'neutral'
474
- if( dominantEmotion !== 'neutral' ) parts.push( `Feeling ${dominantEmotion}` )
474
+ if( dominantEmotion !== 'neutral') parts.push(`Feeling ${dominantEmotion}`)
475
475
 
476
476
  // Active conversation entities — pulls memories about current interlocutors
477
477
  const senderNames = new Set<string>()
478
478
  for( const entity of state.entities.values() ){
479
- if( entity.type !== 'communication' ) continue
479
+ if( entity.type !== 'communication') continue
480
480
  const msgTick = ( entity.metadata?.tick as number ) ?? 0
481
481
  if( state.tick - msgTick > 30 ) continue
482
482
  if( entity.metadata?.processedByExecutive ) continue
483
483
  const name = entity.metadata?.agentName as string | undefined
484
- if( name && name !== 'unknown' ) senderNames.add( name )
484
+ if( name && name !== 'unknown') senderNames.add( name )
485
485
  }
486
- if( senderNames.size > 0 ) parts.push( `Talking with: ${[ ...senderNames ].join( ', ' )}` )
486
+ if( senderNames.size > 0 ) parts.push(`Talking with: ${[ ...senderNames ].join(', ')}`)
487
487
 
488
488
  // Recent percepts (top 3 by salience)
489
489
  const percepts = extractPercepts( state ).slice( 0, 3 )
490
490
  if( percepts.length > 0 ){
491
- parts.push( `Recently observed: ${percepts.map( p => p.summary ).join( '; ' )}` )
491
+ parts.push(`Recently observed: ${percepts.map( p => p.summary ).join('; ')}`)
492
492
  }
493
493
 
494
- return parts.length > 0 ? parts.join( '. ' ) : 'Current situation'
494
+ return parts.length > 0 ? parts.join('. ') : 'Current situation'
495
495
  }
496
496
 
497
497
  /** Pull planIds from recalled plan-descriptor episodes (their content carries planId). */
@@ -500,26 +500,26 @@ function collectPlanIds( episodes: Array<{ content: unknown }> ): string[] {
500
500
  for( const ep of episodes ){
501
501
  const c = ep.content as Record<string, any> | null | undefined
502
502
  const pid = c?.[ 'planId' ] ?? c?.[ 'content' ]?.[ 'planId' ]
503
- if( typeof pid === 'string' ) ids.push( pid )
503
+ if( typeof pid === 'string') ids.push( pid )
504
504
  }
505
505
  return [ ...new Set( ids ) ]
506
506
  }
507
507
 
508
508
  function _extractEpisodeContent( raw: unknown ): string {
509
- if( typeof raw === 'string' ) return raw
509
+ if( typeof raw === 'string') return raw
510
510
  if( typeof raw !== 'object' || raw === null ) return String( raw )
511
511
  const c = raw as Record<string, unknown>
512
512
 
513
513
  // WMItem wrapper: { wmType, content: { description | summary | ... } }
514
514
  // Check wmType first so we correctly unwrap structured WM items.
515
- if( typeof c['wmType'] === 'string' ){
515
+ if( typeof c['wmType'] === 'string'){
516
516
  const inner = c['content']
517
- if( typeof inner === 'string' ) return inner
517
+ if( typeof inner === 'string') return inner
518
518
  if( typeof inner === 'object' && inner !== null ){
519
519
  const ic = inner as Record<string, unknown>
520
- if( typeof ic['description'] === 'string' ) return ic['description']
521
- if( typeof ic['summary'] === 'string' ) return ic['summary']
522
- if( typeof ic['userMessage'] === 'string' ){
520
+ if( typeof ic['description'] === 'string') return ic['description']
521
+ if( typeof ic['summary'] === 'string') return ic['summary']
522
+ if( typeof ic['userMessage'] === 'string'){
523
523
  const reply = typeof ic['willReply'] === 'string' ? ` → "${ic['willReply']}"` : ''
524
524
  return `"${ic['userMessage']}"${reply}`
525
525
  }
@@ -527,23 +527,23 @@ function _extractEpisodeContent( raw: unknown ): string {
527
527
  }
528
528
 
529
529
  // Plain percept WMItem: { summary } or nested { content: { summary } }
530
- if( typeof c['summary'] === 'string' ) return c['summary']
530
+ if( typeof c['summary'] === 'string') return c['summary']
531
531
  const inner = c['content']
532
- if( typeof inner === 'string' ) return inner
532
+ if( typeof inner === 'string') return inner
533
533
  if( typeof inner === 'object' && inner !== null ){
534
534
  const ic = inner as Record<string, unknown>
535
- if( typeof ic['summary'] === 'string' ) return ic['summary']
536
- if( typeof ic['description'] === 'string' ) return ic['description']
535
+ if( typeof ic['summary'] === 'string') return ic['summary']
536
+ if( typeof ic['description'] === 'string') return ic['description']
537
537
  }
538
538
  // Belief: { statement }
539
- if( typeof c['statement'] === 'string' ) return c['statement']
539
+ if( typeof c['statement'] === 'string') return c['statement']
540
540
  // Conversation turn: { userMessage, willReply }
541
- if( typeof c['userMessage'] === 'string' ){
541
+ if( typeof c['userMessage'] === 'string'){
542
542
  const reply = typeof c['willReply'] === 'string' ? ` → "${c['willReply']}"` : ''
543
543
  return `"${c['userMessage']}"${reply}`
544
544
  }
545
545
  // Goal: { description }
546
- if( typeof c['description'] === 'string' ) return c['description']
546
+ if( typeof c['description'] === 'string') return c['description']
547
547
  return JSON.stringify( raw ).slice( 0, 200 )
548
548
  }
549
549
 
@@ -570,10 +570,10 @@ function mapEpisodeToMemory( ep: {
570
570
  }
571
571
 
572
572
  function extractSummary( content: unknown ): string {
573
- if( typeof content === 'string' )
573
+ if( typeof content === 'string')
574
574
  return content.slice( 0, 120 )
575
575
 
576
- if( content && typeof content === 'object' ){
576
+ if( content && typeof content === 'object'){
577
577
  const obj = content as Record<string, unknown>
578
578
 
579
579
  return (obj.summary as string)
@@ -581,7 +581,7 @@ function extractSummary( content: unknown ): string {
581
581
  ?? JSON.stringify( content ).slice( 0, 120 )
582
582
  }
583
583
 
584
- return String( content ?? '' ).slice( 0, 120 )
584
+ return String( content ?? '').slice( 0, 120 )
585
585
  }
586
586
 
587
587
  function extractPercepts( state: ReadonlySimulationState ): Array<{ category: string; summary: string; salience: number }> {
@@ -72,7 +72,7 @@ export class DeferredEffectQueue {
72
72
  flush( state: ReadonlySimulationState, currentTick: number ): void {
73
73
  if( this._entries.length === 0 ) return
74
74
 
75
- const committedTick = state.metrics.get( 'executive.last_tick' )
75
+ const committedTick = state.metrics.get('executive.last_tick')
76
76
  const keep: DeferredEntry[] = []
77
77
 
78
78
  for( const entry of this._entries ){
@@ -87,7 +87,7 @@ export class DeferredEffectQueue {
87
87
  for( const effect of entry.effects ){
88
88
  try { effect() }
89
89
  catch( err ){
90
- logger.error( `[executive] deferred effect failed (tick ${entry.observedTick}):`, err )
90
+ logger.error(`[executive] deferred effect failed (tick ${entry.observedTick}):`, err )
91
91
  }
92
92
  }
93
93
  }
@@ -60,7 +60,7 @@ import {
60
60
  type GatingState
61
61
  } from '#faculties/executive.engine/gating'
62
62
  import { LLMDirector } from '#llm/index'
63
- import type { LLMProvider } from '#llm/index'
63
+ import { defaultModelFor, type LLMProvider } from '#llm/index'
64
64
  import { buildFallbackOutput, parseResponse } from '#faculties/executive.engine/parser'
65
65
  import { selectProcess, ideationTemperature, DELIBERATE_THRESHOLD } from '#faculties/executive.engine/effort.gate'
66
66
  import { proposeCandidates } from '#faculties/executive.engine/deliberate.reasoning'
@@ -102,7 +102,7 @@ export interface ExecutiveEngineConfig {
102
102
  */
103
103
  export function effortTargetForActions( actionTypes: Iterable<string> ): number | null {
104
104
  const types = new Set( actionTypes )
105
- if( types.has( 'focus' ) ) return 1.0
105
+ if( types.has('focus') ) return 1.0
106
106
  if( [ 'rest', 'sleep', 'wait', 'meditate' ].some( t => types.has( t ) ) ) return 0.4
107
107
  return null
108
108
  }
@@ -308,10 +308,10 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
308
308
  d = new LLMDirector( {
309
309
  willId: this._willId!,
310
310
  model,
311
- maxOutputTokens: this._llm?.maxOutputTokens ?? parseInt( process.env.WILL_MAX_OUTPUT_TOKENS ?? '8096' ),
311
+ maxOutputTokens: this._llm?.maxOutputTokens ?? parseInt( process.env.WILL_MAX_OUTPUT_TOKENS ?? '8096'),
312
312
  // Provider-agnostic key; falls back to ANTHROPIC_API_KEY for back-compat.
313
313
  apiKey: this._llm?.apiKey ?? process.env.WILL_LLM_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? '',
314
- provider: ( this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? 'anthropic' ) as LLMProvider,
314
+ provider: ( this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? 'anthropic') as LLMProvider,
315
315
  // Optional base-URL override (e.g. Ollama / Azure / self-hosted). Unset →
316
316
  // the director uses the provider's official endpoint.
317
317
  baseUrl: this._llm?.baseUrl ?? process.env.WILL_LLM_BASE_URL ?? process.env.OPENAI_BASE_URL,
@@ -327,7 +327,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
327
327
  return d
328
328
  }
329
329
 
330
- spawnFacet( role?: 'deliberation' | 'conversation' | 'outreach' | 'supervision' ): { attention: 'available' | 'full', handle?: ExecutiveFacetHandle } {
330
+ spawnFacet( role?: 'deliberation' | 'conversation' | 'outreach' | 'supervision'): { attention: 'available' | 'full', handle?: ExecutiveFacetHandle } {
331
331
  // Delegate to FacetSupervisor (R5-g-3), passing the current engine
332
332
  // attachments. The supervisor owns the registry + attention budget and
333
333
  // performs the throw-checks on bus / director / state ref.
@@ -376,7 +376,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
376
376
 
377
377
  // Set attention state for bandwidth allowance
378
378
  // One facet per ~0.3 free capacity units, floor at 1
379
- if( event.type === 'attention.state.changed' ){
379
+ if( event.type === 'attention.state.changed'){
380
380
  const p = event.payload as { freeFraction: number }
381
381
  this._facetSupervisor.setAttentionState( p.freeFraction )
382
382
  return
@@ -436,7 +436,8 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
436
436
  // Initialize LLM directors if not yet done (requires willId). One director
437
437
  // per distinct role model; roles that share a model share the instance.
438
438
  if( !this._llmDirector && this._willId ){
439
- const execModel = this._models.executive ?? process.env.WILL_LLM_MODEL ?? 'claude-sonnet-4-5-20250929'
439
+ const execModel = this._models.executive ?? process.env.WILL_LLM_MODEL
440
+ ?? defaultModelFor( ( this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? 'anthropic') as LLMProvider )
440
441
  this._llmDirector = this._directorFor( execModel )
441
442
  // The summarizer runs its role's model (falls back to executive) with the
442
443
  // same provider, session logging and token tracking.
@@ -456,7 +457,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
456
457
  updateGatingState( this._gatingState, state, tick, result.shouldActivate, result.cleanedBuffer )
457
458
 
458
459
  if( result.shouldActivate )
459
- logger.info( `[executive] activating — reason: ${result.reason} (tick=${tick})` )
460
+ logger.info(`[executive] activating — reason: ${result.reason} (tick=${tick})`)
460
461
 
461
462
  return result.shouldActivate
462
463
  }
@@ -506,7 +507,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
506
507
  semanticIntegrator: this._semanticIntegrator
507
508
  }, state )
508
509
 
509
- stream.report( 'context_assembled', {
510
+ stream.report('context_assembled', {
510
511
  workingMemoryItems: execContext.workingMemory.length,
511
512
  activeGoals: execContext.goals.length,
512
513
  totalEpisodes: this._episodicConsolidator?.getAllEpisodes().length ?? 0,
@@ -515,7 +516,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
515
516
 
516
517
  // Compute modulation and uncertainty using PromptFactory
517
518
  const qualityModulation = PromptFactory.computeQualityModulation( state )
518
- stream.report( 'modulation', { qualityModulation } )
519
+ stream.report('modulation', { qualityModulation } )
519
520
 
520
521
  const epistemicUncertainty = PromptFactory.computeEpistemicUncertainty( execContext, state )
521
522
  this._lastEpistemicUncertainty = epistemicUncertainty
@@ -525,15 +526,15 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
525
526
  // computed this tick, so the choice is free and deterministic (R2). The threshold is
526
527
  // the *effective* one (base ⊕ persona-prior): an analytical Will develops a lower
527
528
  // threshold and deliberates more readily — effort allocation as a developing trait.
528
- const deliberateThreshold = readEffectiveParams( state, 'engine-config-executive' ).deliberateThreshold ?? DELIBERATE_THRESHOLD
529
+ const deliberateThreshold = readEffectiveParams( state, 'engine-config-executive').deliberateThreshold ?? DELIBERATE_THRESHOLD
529
530
  const processSelection = selectProcess( {
530
531
  epistemicUncertainty,
531
532
  priorConfidence: this._lastExecutiveOutput?.confidence ?? 0.5,
532
- novelty: state.metrics.get( 'perception.novelty' ) ?? 0,
533
- stressLoad: state.metrics.get( 'stress.load' ) ?? 0,
533
+ novelty: state.metrics.get('perception.novelty') ?? 0,
534
+ stressLoad: state.metrics.get('stress.load') ?? 0,
534
535
  hasPendingMessage: this._messageQueue.pendingMessages.length > 0,
535
536
  }, deliberateThreshold )
536
- stream.report( 'process_selected', {
537
+ stream.report('process_selected', {
537
538
  process: processSelection.process,
538
539
  effortScore: processSelection.effortScore,
539
540
  reason: processSelection.reason,
@@ -599,7 +600,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
599
600
  `candidates=${ideationCandidates?.length ?? 0} temp=${proposeTemperature.toFixed( 2 )} latency=${wallClock() - ideationStart}ms`
600
601
  )
601
602
  }
602
- stream.report( 'ideation_complete', {
603
+ stream.report('ideation_complete', {
603
604
  process: processSelection.process,
604
605
  candidateCount: ideationCandidates?.length ?? 0,
605
606
  } )
@@ -638,7 +639,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
638
639
 
639
640
  // Call LLM
640
641
  if( !this._llmDirector )
641
- throw new Error( 'LLM director not initialized — willId must be set before first tick' )
642
+ throw new Error('LLM director not initialized — willId must be set before first tick')
642
643
 
643
644
  const llmStart = wallClock() // perf timing only — latency is telemetry, never replay state
644
645
  let executiveOutput: ExecutiveOutputFull
@@ -667,7 +668,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
667
668
  )
668
669
 
669
670
  const responsePath = this._willId
670
- ? `./data/wills/${this._willId}/debug/response-tick-${String( state.tick ).padStart( 6, '0' )}.txt`
671
+ ? `./data/wills/${this._willId}/debug/response-tick-${String( state.tick ).padStart( 6, '0')}.txt`
671
672
  : ''
672
673
  this._sessionLogger?.write( {
673
674
  type: 'executive.response',
@@ -691,7 +692,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
691
692
  }
692
693
  catch( err: unknown ){
693
694
  const msg = err instanceof Error ? err.message : String( err )
694
- logger.error( `[executive] LLM call failed: ${msg.slice( 0, 200 )}` )
695
+ logger.error(`[executive] LLM call failed: ${msg.slice( 0, 200 )}`)
695
696
 
696
697
  this._sessionLogger?.write( {
697
698
  type: 'executive.response',
@@ -724,7 +725,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
724
725
  hasNarrative: !!executiveOutput.narrative
725
726
  } )
726
727
 
727
- stream.report( 'executive_complete', {
728
+ stream.report('executive_complete', {
728
729
  actionCount: executiveOutput.actions.length,
729
730
  planCount: executiveOutput.plans?.length ?? 0,
730
731
  newBeliefCount: executiveOutput.newBeliefs?.length ?? 0,
@@ -743,7 +744,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
743
744
  ): StateCommands | null {
744
745
  const data = result as Record<string, unknown>
745
746
 
746
- if( step === 'context_assembled' )
747
+ if( step === 'context_assembled')
747
748
  return {
748
749
  metrics: [
749
750
  [ 'executive.phase', 0 ],
@@ -751,7 +752,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
751
752
  ]
752
753
  }
753
754
 
754
- if( step === 'modulation' )
755
+ if( step === 'modulation')
755
756
  return {
756
757
  metrics: [
757
758
  [ 'executive.phase', 1 ],
@@ -759,7 +760,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
759
760
  ]
760
761
  }
761
762
 
762
- if( step === 'process_selected' )
763
+ if( step === 'process_selected')
763
764
  return {
764
765
  metrics: [
765
766
  [ 'executive.process', ( data.process as string ) === 'deliberate' ? 1 : 0 ],
@@ -767,14 +768,14 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
767
768
  ]
768
769
  }
769
770
 
770
- if( step === 'ideation_complete' )
771
+ if( step === 'ideation_complete')
771
772
  return {
772
773
  metrics: [
773
774
  [ 'executive.deliberate_candidates', ( data.candidateCount as number ) ?? 0 ]
774
775
  ]
775
776
  }
776
777
 
777
- if( step === 'executive_complete' )
778
+ if( step === 'executive_complete')
778
779
  return {
779
780
  metrics: [
780
781
  [ 'executive.phase', 2 ],
@@ -1043,7 +1044,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
1043
1044
  private _restoreSummarizer( state: ReadonlySimulationState ): void {
1044
1045
  if( !this._summarizer ) return
1045
1046
 
1046
- const entity = state.entities.get( 'executive-rolling-summary' )
1047
+ const entity = state.entities.get('executive-rolling-summary')
1047
1048
  if( !entity ) return
1048
1049
 
1049
1050
  const m = entity.metadata ?? {}
@@ -1053,6 +1054,6 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
1053
1054
 
1054
1055
  this._summarizer.restore( summary, buffer, callCount )
1055
1056
  if( summary )
1056
- logger.info( `[executive] summarizer restored (${summary.length} chars, ${callCount} prior calls)` )
1057
+ logger.info(`[executive] summarizer restored (${summary.length} chars, ${callCount} prior calls)`)
1057
1058
  }
1058
1059
  }
@@ -140,12 +140,12 @@ export class FacetSupervisor {
140
140
  // vanish silently. The TTL measures *quiet* facets only.
141
141
  if( facet.busy ) continue
142
142
  if( tick - facet.lastActiveTick > this._idleTtlTicks )
143
- this._reap( id, 'idle' )
143
+ this._reap( id, 'idle')
144
144
  }
145
145
  }
146
146
 
147
147
  /** Destroy + deregister a facet and notify its owner. Shared by the reaper + LRU eviction. */
148
- private _reap( facetId: string, reason: 'idle' | 'lru' ): void {
148
+ private _reap( facetId: string, reason: 'idle' | 'lru'): void {
149
149
  const facet = this._facets.get( facetId )
150
150
  if( !facet ) return
151
151
 
@@ -154,7 +154,7 @@ export class FacetSupervisor {
154
154
  const onReaped = this._onReaped.get( facetId )
155
155
  this._onReaped.delete( facetId )
156
156
 
157
- logger.info( `[executive] facet ${facetId} reaped (${reason}); remaining: ${this._facets.size}` )
157
+ logger.info(`[executive] facet ${facetId} reaped (${reason}); remaining: ${this._facets.size}`)
158
158
  this._sessionLogger?.write({
159
159
  type: 'executive.facet.destroy',
160
160
  tick: this._lastStateRef?.tick as unknown as number ?? 0,
@@ -165,7 +165,7 @@ export class FacetSupervisor {
165
165
 
166
166
  // Notify the owner (e.g. AuditionEngine) so it drops its handle + session state.
167
167
  try { onReaped?.() }
168
- catch( err ){ logger.error( `[executive] facet ${facetId} onReaped error:`, err ) }
168
+ catch( err ){ logger.error(`[executive] facet ${facetId} onReaped error:`, err ) }
169
169
  }
170
170
 
171
171
  private _leastRecentlyActive(): string | null {
@@ -198,13 +198,13 @@ export class FacetSupervisor {
198
198
  */
199
199
  spawn( deps: FacetSpawnDeps ): SpawnResult {
200
200
  if( !deps.bus )
201
- throw new Error( 'Cannot spawn facet — CognitiveBus not attached. Was addEngine() called?' )
201
+ throw new Error('Cannot spawn facet — CognitiveBus not attached. Was addEngine() called?')
202
202
 
203
203
  if( !deps.llmDirector )
204
- throw new Error( 'Cannot spawn facet — LLM director not initialized. Set willId first.' )
204
+ throw new Error('Cannot spawn facet — LLM director not initialized. Set willId first.')
205
205
 
206
206
  if( !deps.stateRef )
207
- throw new Error( 'Cannot spawn facet — no state snapshot available. Wait for first tick.' )
207
+ throw new Error('Cannot spawn facet — no state snapshot available. Wait for first tick.')
208
208
 
209
209
  // Authoritative current state ref from the engine — keep it so a later
210
210
  // destroy() logs the same tick the engine would.
@@ -214,15 +214,15 @@ export class FacetSupervisor {
214
214
  const maxFacets = Math.max( 1, Math.floor( this._attentionFreeCapacity / 0.3 ) )
215
215
  if( this._facets.size >= maxFacets ){
216
216
  if( !this._evictLruOnPressure ){
217
- logger.info( `[executive] attention full (${this._facets.size}/${maxFacets} facets) ` )
217
+ logger.info(`[executive] attention full (${this._facets.size}/${maxFacets} facets) `)
218
218
  return { attention: 'full' }
219
219
  }
220
220
  // Budget full but a new conversation arrived — evict the least-recently-active
221
221
  // facet so a fresh, live conversation preempts a stale one (no silent drop).
222
222
  const lru = this._leastRecentlyActive()
223
223
  if( !lru ) return { attention: 'full' } // nothing evictable (shouldn't happen)
224
- logger.info( `[executive] attention full (${this._facets.size}/${maxFacets}) — evicting LRU facet ${lru}` )
225
- this._reap( lru, 'lru' )
224
+ logger.info(`[executive] attention full (${this._facets.size}/${maxFacets}) — evicting LRU facet ${lru}`)
225
+ this._reap( lru, 'lru')
226
226
  }
227
227
 
228
228
  this._facetCounter++
@@ -248,7 +248,7 @@ export class FacetSupervisor {
248
248
 
249
249
  this._facets.set( facetId, facet )
250
250
 
251
- logger.info( `[executive] spawned facet → ${facetId} (total facets: ${this._facets.size})` )
251
+ logger.info(`[executive] spawned facet → ${facetId} (total facets: ${this._facets.size})`)
252
252
 
253
253
  this._sessionLogger?.write({
254
254
  type: 'executive.facet.spawn',
@@ -271,7 +271,7 @@ export class FacetSupervisor {
271
271
  facet.destroy()
272
272
  this._facets.delete( facetId )
273
273
  this._onReaped.delete( facetId ) // explicit close — owner already knows; don't fire onReaped
274
- logger.info( `[executive] facet ${facetId} destroyed (remaining: ${this._facets.size})` )
274
+ logger.info(`[executive] facet ${facetId} destroyed (remaining: ${this._facets.size})`)
275
275
  this._sessionLogger?.write({
276
276
  type: 'executive.facet.destroy',
277
277
  tick: this._lastStateRef?.tick as unknown as number ?? 0,