@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.
- package/README.md +32 -12
- package/dist/channels/discord.d.ts +2 -11
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/whatsapp.d.ts +72 -0
- package/dist/channels/whatsapp.js +252 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/cli.js +837 -91
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +620 -79
- 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/types-E9-HV-SW.d.ts +11 -0
- package/dist/{will-D-slky1N.d.ts → will-Bikuk4s2.d.ts} +56 -12
- package/package.json +12 -3
- 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 +318 -0
- package/src/cli.ts +46 -23
- package/src/cognition/acp.ts +28 -0
- package/src/cognition/agency/consequence.ts +174 -0
- package/src/cognition/agency/engines/action.selector.ts +301 -48
- package/src/cognition/agency/engines/affordance.synthesizer.ts +26 -16
- package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
- package/src/cognition/agency/engines/motor.schema.executor.ts +86 -14
- package/src/cognition/agency/engines/reafference.engine.ts +122 -18
- 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 +1 -1
- package/src/cognition/agency/revocation.ts +79 -0
- package/src/cognition/agency/schemas/repertoire.ts +2 -2
- package/src/cognition/agency/selection.scoring.ts +25 -9
- 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 +27 -26
- 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 +11 -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 +59 -37
- package/src/host/utterances.ts +1 -1
- package/src/llm/index.ts +84 -34
- 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 +20 -11
- package/src/serve/server.ts +12 -12
- package/src/stem/assembly.audit.ts +3 -3
- package/src/stem/guards/identity.coherence.ts +13 -12
- package/src/stem/guards/identity.guard.ts +22 -22
- package/src/stem/index.ts +11 -11
- package/src/stem/mind.ts +12 -12
- package/src/stem/tracts/biography.writer.ts +3 -3
- package/src/stem/tracts/effector.controller.ts +4 -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
|
@@ -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'
|
|
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, ''
|
|
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'
|
|
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 ?? ''
|
|
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'
|
|
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'
|
|
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'
|
|
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(
|
|
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(
|
|
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'
|
|
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'
|
|
437
|
-
if( m.kind === 'thing' || m.kind === 'sentient'
|
|
438
|
-
if( typeof m.reliability === '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(
|
|
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'
|
|
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'
|
|
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'
|
|
484
|
+
if( name && name !== 'unknown') senderNames.add( name )
|
|
485
485
|
}
|
|
486
|
-
if( senderNames.size > 0 ) parts.push(
|
|
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(
|
|
491
|
+
parts.push(`Recently observed: ${percepts.map( p => p.summary ).join('; ')}`)
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
return parts.length > 0 ? parts.join(
|
|
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'
|
|
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'
|
|
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'
|
|
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'
|
|
521
|
-
if( typeof ic['summary'] === 'string'
|
|
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'
|
|
530
|
+
if( typeof c['summary'] === 'string') return c['summary']
|
|
531
531
|
const inner = c['content']
|
|
532
|
-
if( typeof inner === 'string'
|
|
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'
|
|
536
|
-
if( typeof ic['description'] === 'string'
|
|
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'
|
|
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'
|
|
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 ?? ''
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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'
|
|
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'
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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'
|
|
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(
|
|
533
|
-
stressLoad: state.metrics.get(
|
|
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(
|
|
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(
|
|
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(
|
|
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'
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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'
|
|
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(
|
|
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(
|
|
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(
|
|
201
|
+
throw new Error('Cannot spawn facet — CognitiveBus not attached. Was addEngine() called?')
|
|
202
202
|
|
|
203
203
|
if( !deps.llmDirector )
|
|
204
|
-
throw new Error(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|