@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.
Files changed (136) hide show
  1. package/dist/channels/discord.d.ts +1 -1
  2. package/dist/channels/discord.js.map +1 -1
  3. package/dist/channels/whatsapp.d.ts +1 -1
  4. package/dist/channels/whatsapp.js.map +1 -1
  5. package/dist/cli.js +998 -59
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +998 -59
  9. package/dist/index.js.map +1 -1
  10. package/dist/mcp/effectors.d.ts +1 -1
  11. package/dist/mcp/effectors.js.map +1 -1
  12. package/dist/{will-BDq-TMQr.d.ts → will-DAW0l-lY.d.ts} +90 -10
  13. package/package.json +1 -1
  14. package/src/channels/discord.ts +11 -11
  15. package/src/channels/roster.ts +1 -1
  16. package/src/channels/types.ts +1 -1
  17. package/src/channels/whatsapp.ts +25 -25
  18. package/src/cli.ts +20 -20
  19. package/src/cognition/acp.ts +28 -0
  20. package/src/cognition/agency/consequence.ts +174 -0
  21. package/src/cognition/agency/engines/action.selector.ts +333 -48
  22. package/src/cognition/agency/engines/affordance.synthesizer.ts +35 -16
  23. package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
  24. package/src/cognition/agency/engines/motor.schema.executor.ts +90 -14
  25. package/src/cognition/agency/engines/reafference.engine.ts +152 -23
  26. package/src/cognition/agency/execution.primitives.ts +13 -13
  27. package/src/cognition/agency/proactive.communicator.ts +1 -1
  28. package/src/cognition/agency/reconcile.learning.ts +10 -1
  29. package/src/cognition/agency/revocation.ts +79 -0
  30. package/src/cognition/agency/schemas/repertoire.ts +109 -9
  31. package/src/cognition/agency/selection.scoring.ts +32 -10
  32. package/src/cognition/agency/types.ts +9 -0
  33. package/src/cognition/bus.ts +2 -2
  34. package/src/cognition/completion.inbox.ts +1 -1
  35. package/src/cognition/config.mirror.entities.ts +5 -5
  36. package/src/cognition/event.log.ts +2 -2
  37. package/src/cognition/event.schemas.ts +67 -67
  38. package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
  39. package/src/cognition/faculties/affective.blender.ts +36 -4
  40. package/src/cognition/faculties/attachment.evaluator.ts +6 -6
  41. package/src/cognition/faculties/attention.allocator.ts +63 -8
  42. package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
  43. package/src/cognition/faculties/bias.detector.ts +7 -7
  44. package/src/cognition/faculties/circadian.oscillator.ts +3 -3
  45. package/src/cognition/faculties/confidence.calibrator.ts +7 -7
  46. package/src/cognition/faculties/dream.simulator.ts +5 -5
  47. package/src/cognition/faculties/empathy.simulator.ts +7 -7
  48. package/src/cognition/faculties/energy.regulator.ts +4 -4
  49. package/src/cognition/faculties/episodic.consolidator.ts +6 -6
  50. package/src/cognition/faculties/executive.engine/commands.ts +6 -6
  51. package/src/cognition/faculties/executive.engine/context.ts +42 -42
  52. package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
  53. package/src/cognition/faculties/executive.engine/engine.ts +25 -25
  54. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
  55. package/src/cognition/faculties/executive.engine/facet.ts +18 -18
  56. package/src/cognition/faculties/executive.engine/gating.ts +2 -2
  57. package/src/cognition/faculties/executive.engine/messages.ts +3 -3
  58. package/src/cognition/faculties/executive.engine/parser.ts +11 -11
  59. package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
  60. package/src/cognition/faculties/exteroception.ts +99 -5
  61. package/src/cognition/faculties/forgetting.curve.ts +3 -3
  62. package/src/cognition/faculties/frustration.evaluator.ts +6 -6
  63. package/src/cognition/faculties/goal.manager.ts +15 -15
  64. package/src/cognition/faculties/inhibition.controller.ts +3 -3
  65. package/src/cognition/faculties/interoception.ts +3 -3
  66. package/src/cognition/faculties/introspection.engine.ts +3 -3
  67. package/src/cognition/faculties/known.entity.tracker.ts +15 -15
  68. package/src/cognition/faculties/loss.evaluator.ts +2 -2
  69. package/src/cognition/faculties/moral.evaluator.ts +4 -4
  70. package/src/cognition/faculties/novelty.detector.ts +4 -4
  71. package/src/cognition/faculties/persona.consolidator.ts +12 -12
  72. package/src/cognition/faculties/planning.engine/engine.ts +47 -47
  73. package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
  74. package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
  75. package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
  76. package/src/cognition/faculties/reputation.tracker.ts +6 -6
  77. package/src/cognition/faculties/reward.evaluator.ts +4 -4
  78. package/src/cognition/faculties/self.model.updater.ts +8 -8
  79. package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
  80. package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
  81. package/src/cognition/faculties/social.perception.ts +3 -3
  82. package/src/cognition/faculties/spaced.repetition.ts +2 -2
  83. package/src/cognition/faculties/stress.regulator.ts +27 -4
  84. package/src/cognition/faculties/task.switcher.ts +11 -6
  85. package/src/cognition/faculties/theory.of.mind.ts +6 -6
  86. package/src/cognition/faculties/threat.evaluator.ts +3 -3
  87. package/src/cognition/faculties/working.memory.ts +8 -8
  88. package/src/cognition/generative.model.ts +2 -2
  89. package/src/cognition/memory/vector.adapter.ts +5 -5
  90. package/src/cognition/memory/vector.content.ts +4 -4
  91. package/src/cognition/memory/vector.embedder.ts +9 -9
  92. package/src/cognition/persona.prior.ts +1 -1
  93. package/src/cognition/schema.registry.ts +2 -2
  94. package/src/cognition/senses/audition.engine/engine.ts +2 -2
  95. package/src/cognition/senses/base.sense.engine.ts +1 -1
  96. package/src/cognition/utilities/token.tracker.ts +5 -5
  97. package/src/core/abstracts.ts +1 -1
  98. package/src/core/completion.recorder.ts +2 -2
  99. package/src/core/serialization.ts +3 -3
  100. package/src/core/snapshot.manager.ts +1 -1
  101. package/src/core/state.manager.ts +1 -1
  102. package/src/core/utils.ts +1 -1
  103. package/src/host/boot.ts +30 -30
  104. package/src/host/utterances.ts +1 -1
  105. package/src/llm/index.ts +9 -9
  106. package/src/llm/summarizer.ts +4 -4
  107. package/src/llm/wire.contracts.ts +1 -1
  108. package/src/mcp/effectors.ts +10 -10
  109. package/src/mcp/server.ts +11 -11
  110. package/src/pma/eval.ts +1 -1
  111. package/src/pma/index.ts +21 -21
  112. package/src/runners/outreach.runner.ts +3 -3
  113. package/src/runners/social.runner.ts +1 -1
  114. package/src/runners/thin-shim.runner.ts +1 -1
  115. package/src/sdk/will.ts +5 -5
  116. package/src/serve/server.ts +12 -12
  117. package/src/stem/assembly.audit.ts +3 -3
  118. package/src/stem/guards/identity.coherence.ts +10 -10
  119. package/src/stem/guards/identity.guard.ts +22 -22
  120. package/src/stem/index.ts +26 -11
  121. package/src/stem/mind.ts +12 -12
  122. package/src/stem/policy/arbiter.ts +136 -0
  123. package/src/stem/policy/rule.table.ts +172 -0
  124. package/src/stem/policy/verdict.recorder.ts +0 -0
  125. package/src/stem/tracts/biography.writer.ts +3 -3
  126. package/src/stem/tracts/effector.controller.ts +383 -4
  127. package/src/stem/tracts/health.reporter.ts +1 -1
  128. package/src/stem/tracts/outbox.controller.ts +4 -0
  129. package/src/stem/tracts/outbox.writer.ts +4 -4
  130. package/src/stem/tracts/pma.controller.ts +1 -1
  131. package/src/stem/tracts/replay.controller.ts +10 -10
  132. package/src/stem/tracts/sensory.controller.ts +2 -2
  133. package/src/stem/tracts/session.logger.ts +4 -4
  134. package/src/stem/tracts/transport/socketio.transport.ts +7 -7
  135. package/src/stem/tracts/transport/stream.transport.ts +2 -2
  136. package/src/stem/tracts/transport.controller.ts +15 -15
@@ -190,7 +190,7 @@ export class ExecutiveFacet {
190
190
  this._onMasterSync
191
191
  )
192
192
 
193
- logger.info( `[executive.facet] ${facetId} created` )
193
+ logger.info(`[executive.facet] ${facetId} created`)
194
194
  }
195
195
 
196
196
  // ── Public API ─────────────────────────────────────────────
@@ -261,7 +261,7 @@ export class ExecutiveFacet {
261
261
  this._inflight++
262
262
  this._reason( report )
263
263
  .catch( err =>
264
- logger.error( `[executive.facet] ${this.facetId} reasoning error:`, err )
264
+ logger.error(`[executive.facet] ${this.facetId} reasoning error:`, err )
265
265
  )
266
266
  .finally( () => {
267
267
  this._inflight--
@@ -297,10 +297,10 @@ export class ExecutiveFacet {
297
297
  if( this._destroyed ) return
298
298
  this._destroyed = true
299
299
 
300
- this._bus.unsubscribe( `executive-facet-${this.facetId}` )
300
+ this._bus.unsubscribe(`executive-facet-${this.facetId}`)
301
301
  this._listeners.clear()
302
302
 
303
- logger.info( `[executive.facet] ${this.facetId} destroyed` )
303
+ logger.info(`[executive.facet] ${this.facetId} destroyed`)
304
304
  }
305
305
 
306
306
  // ── Master sync ────────────────────────────────────────────
@@ -320,11 +320,11 @@ export class ExecutiveFacet {
320
320
  // Master syncs to all facets or a specific one
321
321
  if( payload.facetId && payload.facetId !== this.facetId ) return
322
322
 
323
- logger.info( `[executive.facet] ${this.facetId} synced from master (tick=${payload.tick})` )
323
+ logger.info(`[executive.facet] ${this.facetId} synced from master (tick=${payload.tick})`)
324
324
 
325
325
  // Store master's latest reasoning for context in next report()
326
326
  if( payload.reasoning )
327
- this._masterSyncHistory.push( `[Master sync — tick ${payload.tick}] ${payload.reasoning.slice( 0, 400 )}` )
327
+ this._masterSyncHistory.push(`[Master sync — tick ${payload.tick}] ${payload.reasoning.slice( 0, 400 )}`)
328
328
 
329
329
  // Keep only last 5 sync entries
330
330
  if( this._masterSyncHistory.length > 5 )
@@ -336,10 +336,10 @@ export class ExecutiveFacet {
336
336
  private async _reason( report: FacetReport ): Promise<void> {
337
337
  // Ensure we have current state
338
338
  if( !this._currentStateRef )
339
- throw new Error( `[executive.facet] ${this.facetId} no state reference available` )
339
+ throw new Error(`[executive.facet] ${this.facetId} no state reference available`)
340
340
 
341
341
  if( !this._currentFocus )
342
- throw new Error( `[executive.facet] ${this.facetId} no focus set. Call setFocus() before report().` )
342
+ throw new Error(`[executive.facet] ${this.facetId} no focus set. Call setFocus() before report().`)
343
343
 
344
344
  const currentState = this._currentStateRef
345
345
 
@@ -377,13 +377,13 @@ export class ExecutiveFacet {
377
377
  // isn't cold on each cycle. Injected before the caller's instructions so the
378
378
  // caller content always comes last (highest recency bias from the LLM).
379
379
  const continuityBlock = this._facetReasoningHistory.length > 0
380
- ? `## My Prior Reasoning (this facet)\n${this._facetReasoningHistory.join( '\n' )}`
380
+ ? `## My Prior Reasoning (this facet)\n${this._facetReasoningHistory.join('\n')}`
381
381
  : ''
382
382
 
383
383
  const reportContent = [
384
384
  continuityBlock,
385
385
  report.instructions ?? ''
386
- ].filter( Boolean ).join( '\n\n' ) || undefined
386
+ ].filter( Boolean ).join('\n\n') || undefined
387
387
 
388
388
  // Dual-process — a facet is "the master over its focus", so it deliberates the same
389
389
  // way. The a-priori effort gate (shared `selectProcess`) picks fast vs deliberate
@@ -391,19 +391,19 @@ export class ExecutiveFacet {
391
391
  // so the Will's deliberativeness is unified across master and every focus. On the
392
392
  // deliberate path a propose pass generates options FOR THIS FOCUS (e.g. a planning
393
393
  // facet's continue/revise/replan/abandon), injected into the decision call below.
394
- const deliberateThreshold = readEffectiveParams( currentState, 'engine-config-executive' ).deliberateThreshold ?? DELIBERATE_THRESHOLD
394
+ const deliberateThreshold = readEffectiveParams( currentState, 'engine-config-executive').deliberateThreshold ?? DELIBERATE_THRESHOLD
395
395
  const processSelection = selectProcess( {
396
396
  epistemicUncertainty,
397
397
  priorConfidence: this._lastConfidence,
398
- novelty: currentState.metrics.get( 'perception.novelty' ) ?? 0,
399
- stressLoad: currentState.metrics.get( 'stress.load' ) ?? 0,
398
+ novelty: currentState.metrics.get('perception.novelty') ?? 0,
399
+ stressLoad: currentState.metrics.get('stress.load') ?? 0,
400
400
  // A facet's "stakes-bearing moment" is a live message awaiting reply (conversation
401
401
  // facets set focus.recallQuery to it); planning/other facets rely on uncertainty.
402
402
  hasPendingMessage: !!this._currentFocus?.recallQuery,
403
403
  }, deliberateThreshold )
404
404
 
405
405
  let ideationCandidates: IdeationCandidate[] | undefined
406
- if( processSelection.process === 'deliberate' ){
406
+ if( processSelection.process === 'deliberate'){
407
407
  const proposeTemperature = ideationTemperature( execContext.identity.traits[ 'creativity' ] ?? 0.5 )
408
408
  const ideationUserMessage = PromptFactory.buildUserMessage( {
409
409
  context: execContext,
@@ -502,7 +502,7 @@ export class ExecutiveFacet {
502
502
  }
503
503
  catch( err ){
504
504
  const msg = err instanceof Error ? err.message : String( err )
505
- logger.error( `[executive.facet] ${this.facetId} LLM call failed: ${msg.slice( 0, 200 )}` )
505
+ logger.error(`[executive.facet] ${this.facetId} LLM call failed: ${msg.slice( 0, 200 )}`)
506
506
 
507
507
  this._sessionLogger?.write( {
508
508
  type: 'executive.facet.response',
@@ -535,7 +535,7 @@ export class ExecutiveFacet {
535
535
  this._lastConfidence = output.confidence
536
536
 
537
537
  // Store reasoning for continuity
538
- this._facetReasoningHistory.push( `[Report: ${report.type}] ${output.reasoning.slice( 0, 400 )}` )
538
+ this._facetReasoningHistory.push(`[Report: ${report.type}] ${output.reasoning.slice( 0, 400 )}`)
539
539
  if( this._facetReasoningHistory.length > 10 )
540
540
  this._facetReasoningHistory = this._facetReasoningHistory.slice( -10 )
541
541
 
@@ -620,10 +620,10 @@ export class ExecutiveFacet {
620
620
  const notify = (): void => {
621
621
  for( const listener of this._listeners )
622
622
  try { listener( decision ) }
623
- catch( err ){ logger.error( `[executive.facet] ${this.facetId} listener error:`, err ) }
623
+ catch( err ){ logger.error(`[executive.facet] ${this.facetId} listener error:`, err ) }
624
624
  }
625
625
 
626
- if( this._inbox ) this._inbox.enqueue( `${this.facetId}:decision`, notify )
626
+ if( this._inbox ) this._inbox.enqueue(`${this.facetId}:decision`, notify )
627
627
  else notify()
628
628
  }
629
629
 
@@ -13,7 +13,7 @@ import type { CognitiveEvent } from '#cognition/bus'
13
13
 
14
14
  function hasPendingInstructions( state: ReadonlySimulationState, pendingMessages: PendingMessage[] ): boolean {
15
15
  for( const entity of state.entities.values() ){
16
- if( entity.type === 'percept' || entity.type === 'percept.social' ){
16
+ if( entity.type === 'percept' || entity.type === 'percept.social'){
17
17
  const salience = (entity.metadata?.salience as number) ?? 0
18
18
  if( salience > 0.7 ) return true
19
19
  }
@@ -209,7 +209,7 @@ export function updateGatingState(
209
209
  // Update crisis counters
210
210
  let activeGoalCount = 0
211
211
  for( const entity of state.entities.values() )
212
- if( entity.type === 'goal' && entity.metadata?.status === 'active' )
212
+ if( entity.type === 'goal' && entity.metadata?.status === 'active')
213
213
  activeGoalCount++
214
214
 
215
215
  const valence = state.metrics.get('affect.valence') ?? 0
@@ -28,7 +28,7 @@ export class MessageQueue {
28
28
  const seenIds = new Set( this.pendingMessages.map( m => m.id ) )
29
29
 
30
30
  for( const [ id, entity ] of state.entities ){
31
- if( entity.type !== 'communication' ) continue
31
+ if( entity.type !== 'communication') continue
32
32
  if( entity.metadata?.processedByExecutive ) continue
33
33
  if( seenIds.has( id ) ) continue
34
34
 
@@ -74,7 +74,7 @@ export class MessageQueue {
74
74
  getVisibleMessageIds( state: ReadonlySimulationState, tick: Tick ): Set<string> {
75
75
  const ids = new Set<string>( this.pendingMessages.map( m => m.id ) )
76
76
  for( const [ id, entity ] of state.entities ){
77
- if( entity.type !== 'communication' ) continue
77
+ if( entity.type !== 'communication') continue
78
78
 
79
79
  const msgTick = (entity.metadata?.tick as number) ?? 0
80
80
  if( tick - msgTick > 30 ) continue
@@ -91,7 +91,7 @@ export class MessageQueue {
91
91
  getStaleMessageIds( state: ReadonlySimulationState, tick: Tick ): string[] {
92
92
  const stale: string[] = []
93
93
  for( const [ id, entity ] of state.entities ){
94
- if( entity.type !== 'communication' ) continue
94
+ if( entity.type !== 'communication') continue
95
95
 
96
96
  const msgTick = (entity.metadata?.tick as number) ?? 0
97
97
  tick - msgTick > 50 && stale.push( id )
@@ -44,7 +44,7 @@ export function parseResponse(
44
44
  }
45
45
  catch {
46
46
  // Strategy 2: balanced-bracket extractor
47
- const actionsStr = extractBalancedArray( fullText, 'actions' )
47
+ const actionsStr = extractBalancedArray( fullText, 'actions')
48
48
  if( !actionsStr) {
49
49
  logger.warn('[executive] No actions found in response — using fallback')
50
50
  return buildFallbackOutput( state, recentActionTypes )
@@ -91,10 +91,10 @@ export function parseIdeation( responseText: string ): IdeationOutput {
91
91
  .map( c => {
92
92
  const o = ( c ?? {} ) as Record<string, unknown>
93
93
  return {
94
- approach: String( o.approach ?? '' ).trim(),
95
- description: String( o.description ?? '' ).trim(),
96
- upside: String( o.upside ?? '' ).trim(),
97
- risk: String( o.risk ?? '' ).trim(),
94
+ approach: String( o.approach ?? '').trim(),
95
+ description: String( o.description ?? '').trim(),
96
+ upside: String( o.upside ?? '').trim(),
97
+ risk: String( o.risk ?? '').trim(),
98
98
  }
99
99
  } )
100
100
  .filter( c => c.approach.length > 0 || c.description.length > 0 )
@@ -109,7 +109,7 @@ export function parseIdeation( responseText: string ): IdeationOutput {
109
109
  catch { /* fall through to bracket extraction */ }
110
110
 
111
111
  // Strategy 2: balanced-bracket extraction of the `candidates` array.
112
- const arrStr = extractBalancedArray( text, 'candidates' )
112
+ const arrStr = extractBalancedArray( text, 'candidates')
113
113
  if( arrStr ){
114
114
  try { return { candidates: coerce( JSON.parse( arrStr ) ) } }
115
115
  catch { /* fall through to empty */ }
@@ -145,15 +145,15 @@ function extractBalancedArray( text: string, key: string ): string | null {
145
145
  continue
146
146
  }
147
147
 
148
- if( ch === '"' ){
148
+ if( ch === '"'){
149
149
  inString = !inString
150
150
  continue
151
151
  }
152
152
 
153
153
  if( inString ) continue
154
154
 
155
- if( ch === '[' || ch === '{' ) depth++
156
- else if( ch === ']' || ch === '}' ){
155
+ if( ch === '[' || ch === '{') depth++
156
+ else if( ch === ']' || ch === '}'){
157
157
  depth--
158
158
 
159
159
  if( depth === 0 )
@@ -196,7 +196,7 @@ function parseTaggedBlocks(
196
196
  ],
197
197
  found = taggedTypes.filter( t => text.includes(`[${t}]`) )
198
198
  if( found.length > 0 ){
199
- const closed = found.map( t => `${t}: ${text.includes(`[/${t}]`) ? 'CLOSED' : 'UNCLOSED'}` ).join(', ')
199
+ const closed = found.map( t => `${t}: ${text.includes(`[/${t}]`) ? 'CLOSED' : 'UNCLOSED'}`).join(', ')
200
200
  logger.info(`[executive] TAGGED BLOCKS: ${closed}`)
201
201
  }
202
202
 
@@ -362,7 +362,7 @@ export function buildFallbackOutput(
362
362
  }
363
363
  else {
364
364
  // Vary the fallback when low-effort actions have dominated recently
365
- const monotonous = recentActionTypes.filter( t => t === 'reflect' || t === 'observe' ).length >= 3
365
+ const monotonous = recentActionTypes.filter( t => t === 'reflect' || t === 'observe').length >= 3
366
366
  if( monotonous) {
367
367
  const alternatives = ['explore', 'learn', 'express_emotion', 'rest']
368
368
  const tick = state.tick as number
@@ -293,15 +293,15 @@ export class PromptFactory {
293
293
  const stat = identity.traitStats?.[ t.k ]
294
294
  if( stat ){
295
295
  const norm = normEmphasis( t.v, stat.mean ) // B — vs my own norm
296
- if( norm ) quals.push( `${norm} my norm` )
297
- if( stat.shiftDir > 0 ) quals.push( 'rising lately' ) // C — recent shift
298
- else if( stat.shiftDir < 0 ) quals.push( 'easing lately' )
296
+ if( norm ) quals.push(`${norm} my norm`)
297
+ if( stat.shiftDir > 0 ) quals.push('rising lately') // C — recent shift
298
+ else if( stat.shiftDir < 0 ) quals.push('easing lately')
299
299
  }
300
- return `${t.k} (${quals.join( ', ' )})`
300
+ return `${t.k} (${quals.join(', ')})`
301
301
  }
302
302
 
303
303
  const traitsLine = notableTraits.length > 0
304
- ? `**Traits:** ${notableTraits.map( surfaceTrait ).join( ', ' )}`
304
+ ? `**Traits:** ${notableTraits.map( surfaceTrait ).join(', ')}`
305
305
  : ''
306
306
 
307
307
  const bd = context.behavioralDisposition
@@ -312,17 +312,17 @@ export class PromptFactory {
312
312
  : ''
313
313
 
314
314
  const selfTuningLine = context.selfTuning && context.selfTuning.length > 0
315
- ? `**Self-tuning (how I've adapted my own mind):** ${context.selfTuning.join( '; ' )}. `
315
+ ? `**Self-tuning (how I've adapted my own mind):** ${context.selfTuning.join('; ')}. `
316
316
  + `These are involuntary adjustments my own faculties have made in response to patterns they noticed in me — not deliberate choices. I can reflect on why they happened.`
317
317
  : ''
318
318
 
319
319
  const identityBlock = [
320
- `**Values:** ${identity.values.length > 0 ? identity.values.join( ', ' ) : 'No values defined yet.'}`,
320
+ `**Values:** ${identity.values.length > 0 ? identity.values.join(', ') : 'No values defined yet.'}`,
321
321
  traitsLine,
322
322
  behavioralLine,
323
323
  selfTuningLine,
324
324
  `**Communication style:** ${identity.style}`,
325
- ].filter( Boolean ).join( '\n' )
325
+ ].filter( Boolean ).join('\n')
326
326
 
327
327
  // Mode-aware role description — master is the cognitive core;
328
328
  // a facet is a focused attentional instance with shared identity.
@@ -344,7 +344,7 @@ export class PromptFactory {
344
344
  const cleanIdentityPrompt = identity.prompt
345
345
  // Strip a forged/duplicated "## Who I Am" / "## Who You Are" *header* (PMA
346
346
  // templates include it) while keeping the persona content beneath it.
347
- .replace( /^##\s*Who (?:I Am|You Are)[^\n]*\n?/m, '' )
347
+ .replace( /^##\s*Who (?:I Am|You Are)[^\n]*\n?/m, '')
348
348
  .trim()
349
349
 
350
350
  return `${cleanIdentityPrompt}
@@ -596,7 +596,7 @@ completionType guide:
596
596
  focusSection,
597
597
  focus.instructions ? `## Focus Instructions\n${focus.instructions.trim()}` : '',
598
598
  reportContent ? `## Current Report\n${reportContent.trim()}` : '',
599
- ].filter( Boolean ).join( '\n\n' )
599
+ ].filter( Boolean ).join('\n\n')
600
600
 
601
601
  const outputFormatBlock = outputFormat
602
602
  ? `\n\n${outputFormat}`
@@ -607,8 +607,8 @@ completionType guide:
607
607
  const ideationBlock = ( ideationCandidates && ideationCandidates.length > 0 )
608
608
  ? `## Candidate Approaches (I generated these — weigh them, then commit)\n${
609
609
  ideationCandidates
610
- .map( ( c, i ) => `${i + 1}. **${c.approach || c.description}** — ${c.description}\n ↑ upside: ${c.upside}\n ↓ risk: ${c.risk}` )
611
- .join( '\n' )
610
+ .map( ( c, i ) => `${i + 1}. **${c.approach || c.description}** — ${c.description}\n ↑ upside: ${c.upside}\n ↓ risk: ${c.risk}`)
611
+ .join('\n')
612
612
  }\n\nChoose among (or improve on) these, then in "reasoning" say briefly why I rejected the others.`
613
613
  : ''
614
614
 
@@ -628,10 +628,10 @@ ${energyGuidance}${stressGuidance}${sleepGuidance}${energyBudget}`
628
628
  Dominant emotion: ${context.affect.dominantEmotion}
629
629
  Valence: ${context.affect.valence.toFixed( 2 )} (${context.affect.valence > 0 ? 'positive' : 'negative'})
630
630
  Arousal: ${context.affect.arousal.toFixed( 2 )} (${context.affect.arousal > 0.6 ? 'highly activated' : 'calm'})
631
- Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.length > 0 ? `\nBlended states: ${context.affect.blends.join( ', ' )}` : ''}`
631
+ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.length > 0 ? `\nBlended states: ${context.affect.blends.join(', ')}` : ''}`
632
632
 
633
633
  // ── Scope-gated cognitive sections (each '' when out of scope or empty) ──
634
- const goalsBlock = has( 'goals' )
634
+ const goalsBlock = has('goals')
635
635
  ? `## Active Goals\n${context.goals.map( g => {
636
636
  const currentTick = state.tick as unknown as number
637
637
  const isOverdue = g.deadline !== undefined && currentTick > g.deadline
@@ -640,22 +640,22 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
640
640
  ? ` [last action: ${g.lastActionType ?? 'action'} @ tick ${g.lastActionAttemptTick}]`
641
641
  : ''
642
642
  return `- [${g.id}]${overdueTag} ${g.description} (priority: ${( g.priority * 100 ).toFixed( 0 )}%, progress: ${( g.progress * 100 ).toFixed( 0 )}%, status: ${g.status}${actionHint})`
643
- } ).join( '\n' ) || 'No active goals'}`
643
+ } ).join('\n') || 'No active goals'}`
644
644
  : ''
645
645
 
646
646
  // Master sees all plans; a facet's plans are scoped by requester (entityId)
647
647
  // and/or recall relevance (relevantPlanIds — recall-scoped awareness, Stage 2).
648
648
  const planRelevantIds = mode === 'master' ? undefined : context.relevantPlanIds
649
- const plansBlock = has( 'plans' )
649
+ const plansBlock = has('plans')
650
650
  ? this._buildActivePlansSection( context.plans, focus.awarenessEntityId, planRelevantIds ).trim()
651
651
  : ''
652
652
 
653
- const recentOutcomesBlock = has( 'recentActions' )
653
+ const recentOutcomesBlock = has('recentActions')
654
654
  ? this._buildRecentOutcomesSection( context.recentActions, state.tick ).trim()
655
655
  : ''
656
656
 
657
- const perceptsBlock = has( 'percepts' )
658
- ? `## Percepts (What I Notice)\n${context.percepts.slice( 0, 10 ).map( p => `- [${p.category}] ${p.summary} (salience: ${p.salience.toFixed( 2 )})` ).join( '\n' ) || 'Nothing notable'}`
657
+ const perceptsBlock = has('percepts')
658
+ ? `## Percepts (What I Notice)\n${context.percepts.slice( 0, 10 ).map( p => `- [${p.category}] ${p.summary} (salience: ${p.salience.toFixed( 2 )})`).join('\n') || 'Nothing notable'}`
659
659
  : ''
660
660
 
661
661
  // Host abilities afforded right now + what each is for. Framed as
@@ -664,19 +664,19 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
664
664
  const abilitiesBlock = ( context.abilities && context.abilities.length > 0 )
665
665
  ? `## Abilities Available Now\nThings I can do in this situation — name one as an action's "type" (with "args" for any specifics it needs) and my body enacts it:\n${context.abilities.map( a =>
666
666
  `- **${a.name}**${a.target ? ` (toward ${a.target})` : ''}${a.description ? ` — ${a.description}` : ''}`
667
- ).join( '\n' )}`
667
+ ).join('\n')}`
668
668
  : ''
669
669
 
670
- const ruminationsBlock = has( 'ruminations' )
671
- ? `## Active Ruminations (retrieved memories & thoughts)\n${context.workingMemory.map( w => `- [${w.type}] ${w.summary} (activation: ${w.activation.toFixed( 2 )})` ).join( '\n' ) || 'Nothing actively held in mind'}`
670
+ const ruminationsBlock = has('ruminations')
671
+ ? `## Active Ruminations (retrieved memories & thoughts)\n${context.workingMemory.map( w => `- [${w.type}] ${w.summary} (activation: ${w.activation.toFixed( 2 )})`).join('\n') || 'Nothing actively held in mind'}`
672
672
  : ''
673
673
 
674
- const memoriesBlock = has( 'memories' )
674
+ const memoriesBlock = has('memories')
675
675
  ? this._buildMemoriesSection( context.memories, state.tick )
676
676
  : ''
677
677
 
678
- const beliefsBlock = has( 'beliefs' )
679
- ? `## My Beliefs\n${context.beliefs.map( b => `- [${b.category}] ${b.statement} (confidence: ${( b.confidence * 100 ).toFixed( 0 )}%)` ).join( '\n' ) || 'No strong beliefs yet'}${context.beliefsOmitted > 0 ? `\n[+${context.beliefsOmitted} omitted — deduped or lower-ranked; full store intact]` : ''}`
678
+ const beliefsBlock = has('beliefs')
679
+ ? `## My Beliefs\n${context.beliefs.map( b => `- [${b.category}] ${b.statement} (confidence: ${( b.confidence * 100 ).toFixed( 0 )}%)`).join('\n') || 'No strong beliefs yet'}${context.beliefsOmitted > 0 ? `\n[+${context.beliefsOmitted} omitted — deduped or lower-ranked; full store intact]` : ''}`
680
680
  : ''
681
681
 
682
682
  // The Will's social models — its read on the people it knows (theory-of-mind, trust,
@@ -685,15 +685,15 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
685
685
  const socialBlock = ( context.knownEntities && context.knownEntities.length > 0 )
686
686
  ? `## People I Know\n${context.knownEntities.map( s => {
687
687
  const bits: string[] = []
688
- if( s.intention ) bits.push( `seems to want: ${s.intention}` )
689
- if( s.emotion ) bits.push( `seems to feel: ${s.emotion}` )
690
- if( s.trust != null ) bits.push( `trust: ${( s.trust * 100 ).toFixed( 0 )}%` )
691
- if( s.reliability != null && s.reliability !== 0.5 ) bits.push( `reliability: ${( s.reliability * 100 ).toFixed( 0 )}%` )
692
- if( s.closeness != null && s.closeness > 0.1 ) bits.push( `closeness: ${( s.closeness * 100 ).toFixed( 0 )}%` )
688
+ if( s.intention ) bits.push(`seems to want: ${s.intention}`)
689
+ if( s.emotion ) bits.push(`seems to feel: ${s.emotion}`)
690
+ if( s.trust != null ) bits.push(`trust: ${( s.trust * 100 ).toFixed( 0 )}%`)
691
+ if( s.reliability != null && s.reliability !== 0.5 ) bits.push(`reliability: ${( s.reliability * 100 ).toFixed( 0 )}%`)
692
+ if( s.closeness != null && s.closeness > 0.1 ) bits.push(`closeness: ${( s.closeness * 100 ).toFixed( 0 )}%`)
693
693
  // The Will can know *someone* without their name yet — never leak the raw keid.
694
- const who = s.name ?? ( s.kind === 'thing' ? 'something' : 'someone' )
695
- return `- ${who}${bits.length ? ' — ' + bits.join( ', ' ) : ''}`
696
- } ).join( '\n' )}`
694
+ const who = s.name ?? ( s.kind === 'thing' ? 'something' : 'someone')
695
+ return `- ${who}${bits.length ? ' — ' + bits.join(', ') : ''}`
696
+ } ).join('\n')}`
697
697
  : ''
698
698
 
699
699
  // Task focus — what the Will is committed to and the felt cost of switching away.
@@ -728,7 +728,7 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
728
728
  identityNudge.trim(),
729
729
  ideationBlock,
730
730
  tailSections,
731
- ].filter( Boolean ).join( '\n\n' )
731
+ ].filter( Boolean ).join('\n\n')
732
732
 
733
733
  return `${body}${outputFormatBlock}`
734
734
  }
@@ -742,7 +742,7 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
742
742
  * @param mode - 'facet' excludes REPLY from the available-tags list since
743
743
  * facets never send messages.
744
744
  */
745
- static buildOutputFormatInstruction( mode: 'master' | 'facet' = 'master' ): string {
745
+ static buildOutputFormatInstruction( mode: 'master' | 'facet' = 'master'): string {
746
746
  const availableTags = 'PLANS, BELIEFS, INTROSPECTION, NARRATIVE, IDENTITY, GOALS_NEW, GOALS_ABANDON, GOALS_REPRIORITIZE, SELF_OBS'
747
747
 
748
748
  return `\n\n## Response Format (REQUIRED)
@@ -801,10 +801,10 @@ Respond with a single JSON object (optionally wrapped in a \`\`\`json code block
801
801
  * Compute quality modulation from physiological state metrics.
802
802
  */
803
803
  static computeQualityModulation( state: ReadonlySimulationState ): number {
804
- const sleepDegradation = state.metrics.get( 'modulation.working_memory_degradation' ) ?? 1
805
- const stressZone = state.metrics.get( 'stress.zone' ) ?? 0
806
- const cognitivePhase = state.metrics.get( 'circadian.cognitive_phase' ) ?? 0.5
807
- const energyDegradation = state.metrics.get( 'modulation.energy_degradation' ) ?? 1
804
+ const sleepDegradation = state.metrics.get('modulation.working_memory_degradation') ?? 1
805
+ const stressZone = state.metrics.get('stress.zone') ?? 0
806
+ const cognitivePhase = state.metrics.get('circadian.cognitive_phase') ?? 0.5
807
+ const energyDegradation = state.metrics.get('modulation.energy_degradation') ?? 1
808
808
  const stressFactor = stressZone <= 1 ? 1.0 : stressZone <= 2 ? 0.8 : 0.5
809
809
  return sleepDegradation * stressFactor * ( 0.8 + cognitivePhase * 0.4 ) * energyDegradation
810
810
  }
@@ -821,7 +821,7 @@ Respond with a single JSON object (optionally wrapped in a \`\`\`json code block
821
821
  const avgConf = beliefCount > 0
822
822
  ? context.beliefs.reduce( ( s, b ) => s + b.confidence, 0 ) / beliefCount
823
823
  : 0
824
- const episodicSize = state.metrics.get( 'memory.episodic_total' ) ?? 0
824
+ const episodicSize = state.metrics.get('memory.episodic_total') ?? 0
825
825
  const topSalience = context.percepts[ 0 ]?.salience ?? 0
826
826
 
827
827
  const certainty = 0.30 * Math.min( beliefCount / 50, 1 ) +
@@ -902,13 +902,13 @@ Rest and sleep RESTORE energy. All other actions CONSUME energy. Do not let ener
902
902
  if( recentActionTypes.length === 0 ) return ''
903
903
 
904
904
  const recent = recentActionTypes
905
- const reflectCount = recent.filter( t => t === 'reflect' || t === 'observe' ).length
905
+ const reflectCount = recent.filter( t => t === 'reflect' || t === 'observe').length
906
906
  const warning = reflectCount >= 3
907
- ? `\n⚠️ **Action variety alert**: "${recent.filter( t => t === 'reflect' || t === 'observe' ).join( '", "' )}" dominated my last ${recent.length} cycles. Choose something DIFFERENT this cycle — e.g. learn, express_emotion, explore, communicate, set_goal, or rest.`
907
+ ? `\n⚠️ **Action variety alert**: "${recent.filter( t => t === 'reflect' || t === 'observe').join('", "')}" dominated my last ${recent.length} cycles. Choose something DIFFERENT this cycle — e.g. learn, express_emotion, explore, communicate, set_goal, or rest.`
908
908
  : ''
909
909
 
910
910
  return `## Recent Actions (last ${recent.length})
911
- ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
911
+ ${recent.map( ( t, i ) => `${i + 1}. ${t}`).join(' → ')}${warning}
912
912
 
913
913
  `
914
914
  }
@@ -953,7 +953,7 @@ ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
953
953
 
954
954
  const omitted = memories.length - lines.length
955
955
  const tail = omitted > 0 ? `\n[+${omitted} omitted — over recall budget; full store intact]` : ''
956
- return `## Relevant Memories\n${lines.join( '\n' )}${tail}`
956
+ return `## Relevant Memories\n${lines.join('\n')}${tail}`
957
957
  }
958
958
 
959
959
  private static _buildRecentOutcomesSection(
@@ -977,12 +977,12 @@ ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
977
977
  return `- ${badge} **${a.type}** (tick ${a.tick}, ${age} ticks ago${planCtx})${outcome}`
978
978
  } )
979
979
 
980
- const hasTimeout = recentActions.some( a => a.status === 'timed_out' )
980
+ const hasTimeout = recentActions.some( a => a.status === 'timed_out')
981
981
  const timeoutNote = hasTimeout
982
982
  ? '\n⚠️ **One or more actions timed out** — my body dispatched them but received no confirmation. Check if the external handler is working, or choose a different approach.'
983
983
  : ''
984
984
 
985
- return `## Recent Action Outcomes\n${lines.join( '\n' )}${timeoutNote}\n\n`
985
+ return `## Recent Action Outcomes\n${lines.join('\n')}${timeoutNote}\n\n`
986
986
  }
987
987
 
988
988
  /**
@@ -1011,7 +1011,7 @@ ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
1011
1011
 
1012
1012
  return `## Active Plans
1013
1013
  Set "planId" in a [PLANS] op to act on one of these; omit it to draft a new plan (I can run several per goal).
1014
- ${lines.join( '\n' )}
1014
+ ${lines.join('\n')}
1015
1015
 
1016
1016
  `
1017
1017
  }
@@ -1020,7 +1020,7 @@ ${lines.join( '\n' )}
1020
1020
  let latest: { updatedAt: number; meta: Record<string, unknown> } | null = null
1021
1021
 
1022
1022
  for( const entity of state.entities.values() ){
1023
- if( entity.type !== 'introspection' ) continue
1023
+ if( entity.type !== 'introspection') continue
1024
1024
 
1025
1025
  if( !latest || entity.updatedAt > latest.updatedAt )
1026
1026
  latest = { updatedAt: entity.updatedAt, meta: entity.metadata ?? {} }
@@ -1036,9 +1036,9 @@ ${lines.join( '\n' )}
1036
1036
  const recommendations = ( latest.meta[ 'recommendations' ] as string[] ) ?? []
1037
1037
 
1038
1038
  let section = `## Recent Self-Reflection\n${explanation}`
1039
- if( biases.length > 0 ) section += `\nPatterns noticed: ${biases.join( '; ' )}`
1040
- if( lessons.length > 0 ) section += `\nLessons learned: ${lessons.join( '; ' )}`
1041
- if( recommendations.length > 0 ) section += `\nRecommendations: ${recommendations.join( '; ' )}`
1039
+ if( biases.length > 0 ) section += `\nPatterns noticed: ${biases.join('; ')}`
1040
+ if( lessons.length > 0 ) section += `\nLessons learned: ${lessons.join('; ')}`
1041
+ if( recommendations.length > 0 ) section += `\nRecommendations: ${recommendations.join('; ')}`
1042
1042
 
1043
1043
  return section + '\n\n'
1044
1044
  }
@@ -1057,15 +1057,15 @@ ${lines.join( '\n' )}
1057
1057
 
1058
1058
  const GENERIC_STYLES = new Set([ 'natural and authentic', 'natural', 'authentic', '' ])
1059
1059
  const valuesEmpty = identity.values.length === 0
1060
- const styleGeneric = GENERIC_STYLES.has( ( identity.style ?? '' ).toLowerCase() )
1060
+ const styleGeneric = GENERIC_STYLES.has( ( identity.style ?? '').toLowerCase() )
1061
1061
 
1062
1062
  if( !valuesEmpty && !styleGeneric ) return ''
1063
1063
 
1064
1064
  const hints: string[] = []
1065
- if( valuesEmpty ) hints.push( 'My values list is empty — reflecting on what matters to me will help ground my decisions. Consider adding a `[IDENTITY_UPDATE]` block with `"values"` this cycle.' )
1066
- if( styleGeneric ) hints.push( 'My communication style is still generic — what truly characterises how I speak? A note in `[IDENTITY_UPDATE]` with `"style"` will make my voice more distinctly mine.' )
1065
+ if( valuesEmpty ) hints.push('My values list is empty — reflecting on what matters to me will help ground my decisions. Consider adding a `[IDENTITY_UPDATE]` block with `"values"` this cycle.')
1066
+ if( styleGeneric ) hints.push('My communication style is still generic — what truly characterises how I speak? A note in `[IDENTITY_UPDATE]` with `"style"` will make my voice more distinctly mine.')
1067
1067
 
1068
- return `\n\n## 💡 Identity Reflection (every ${NUDGE_INTERVAL} ticks)\n${hints.join( '\n' )}`
1068
+ return `\n\n## 💡 Identity Reflection (every ${NUDGE_INTERVAL} ticks)\n${hints.join('\n')}`
1069
1069
  }
1070
1070
  }
1071
1071