@mindot/will 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/channels/discord.d.ts +1 -1
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/channels/whatsapp.js.map +1 -1
- package/dist/cli.js +998 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +998 -59
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/mcp/effectors.js.map +1 -1
- package/dist/{will-BDq-TMQr.d.ts → will-DAW0l-lY.d.ts} +90 -10
- package/package.json +1 -1
- package/src/channels/discord.ts +11 -11
- package/src/channels/roster.ts +1 -1
- package/src/channels/types.ts +1 -1
- package/src/channels/whatsapp.ts +25 -25
- package/src/cli.ts +20 -20
- package/src/cognition/acp.ts +28 -0
- package/src/cognition/agency/consequence.ts +174 -0
- package/src/cognition/agency/engines/action.selector.ts +333 -48
- package/src/cognition/agency/engines/affordance.synthesizer.ts +35 -16
- package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
- package/src/cognition/agency/engines/motor.schema.executor.ts +90 -14
- package/src/cognition/agency/engines/reafference.engine.ts +152 -23
- package/src/cognition/agency/execution.primitives.ts +13 -13
- package/src/cognition/agency/proactive.communicator.ts +1 -1
- package/src/cognition/agency/reconcile.learning.ts +10 -1
- package/src/cognition/agency/revocation.ts +79 -0
- package/src/cognition/agency/schemas/repertoire.ts +109 -9
- package/src/cognition/agency/selection.scoring.ts +32 -10
- package/src/cognition/agency/types.ts +9 -0
- package/src/cognition/bus.ts +2 -2
- package/src/cognition/completion.inbox.ts +1 -1
- package/src/cognition/config.mirror.entities.ts +5 -5
- package/src/cognition/event.log.ts +2 -2
- package/src/cognition/event.schemas.ts +67 -67
- package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
- package/src/cognition/faculties/affective.blender.ts +36 -4
- package/src/cognition/faculties/attachment.evaluator.ts +6 -6
- package/src/cognition/faculties/attention.allocator.ts +63 -8
- package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
- package/src/cognition/faculties/bias.detector.ts +7 -7
- package/src/cognition/faculties/circadian.oscillator.ts +3 -3
- package/src/cognition/faculties/confidence.calibrator.ts +7 -7
- package/src/cognition/faculties/dream.simulator.ts +5 -5
- package/src/cognition/faculties/empathy.simulator.ts +7 -7
- package/src/cognition/faculties/energy.regulator.ts +4 -4
- package/src/cognition/faculties/episodic.consolidator.ts +6 -6
- package/src/cognition/faculties/executive.engine/commands.ts +6 -6
- package/src/cognition/faculties/executive.engine/context.ts +42 -42
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
- package/src/cognition/faculties/executive.engine/engine.ts +25 -25
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
- package/src/cognition/faculties/executive.engine/facet.ts +18 -18
- package/src/cognition/faculties/executive.engine/gating.ts +2 -2
- package/src/cognition/faculties/executive.engine/messages.ts +3 -3
- package/src/cognition/faculties/executive.engine/parser.ts +11 -11
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
- package/src/cognition/faculties/exteroception.ts +99 -5
- package/src/cognition/faculties/forgetting.curve.ts +3 -3
- package/src/cognition/faculties/frustration.evaluator.ts +6 -6
- package/src/cognition/faculties/goal.manager.ts +15 -15
- package/src/cognition/faculties/inhibition.controller.ts +3 -3
- package/src/cognition/faculties/interoception.ts +3 -3
- package/src/cognition/faculties/introspection.engine.ts +3 -3
- package/src/cognition/faculties/known.entity.tracker.ts +15 -15
- package/src/cognition/faculties/loss.evaluator.ts +2 -2
- package/src/cognition/faculties/moral.evaluator.ts +4 -4
- package/src/cognition/faculties/novelty.detector.ts +4 -4
- package/src/cognition/faculties/persona.consolidator.ts +12 -12
- package/src/cognition/faculties/planning.engine/engine.ts +47 -47
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
- package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
- package/src/cognition/faculties/reputation.tracker.ts +6 -6
- package/src/cognition/faculties/reward.evaluator.ts +4 -4
- package/src/cognition/faculties/self.model.updater.ts +8 -8
- package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
- package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
- package/src/cognition/faculties/social.perception.ts +3 -3
- package/src/cognition/faculties/spaced.repetition.ts +2 -2
- package/src/cognition/faculties/stress.regulator.ts +27 -4
- package/src/cognition/faculties/task.switcher.ts +11 -6
- package/src/cognition/faculties/theory.of.mind.ts +6 -6
- package/src/cognition/faculties/threat.evaluator.ts +3 -3
- package/src/cognition/faculties/working.memory.ts +8 -8
- package/src/cognition/generative.model.ts +2 -2
- package/src/cognition/memory/vector.adapter.ts +5 -5
- package/src/cognition/memory/vector.content.ts +4 -4
- package/src/cognition/memory/vector.embedder.ts +9 -9
- package/src/cognition/persona.prior.ts +1 -1
- package/src/cognition/schema.registry.ts +2 -2
- package/src/cognition/senses/audition.engine/engine.ts +2 -2
- package/src/cognition/senses/base.sense.engine.ts +1 -1
- package/src/cognition/utilities/token.tracker.ts +5 -5
- package/src/core/abstracts.ts +1 -1
- package/src/core/completion.recorder.ts +2 -2
- package/src/core/serialization.ts +3 -3
- package/src/core/snapshot.manager.ts +1 -1
- package/src/core/state.manager.ts +1 -1
- package/src/core/utils.ts +1 -1
- package/src/host/boot.ts +30 -30
- package/src/host/utterances.ts +1 -1
- package/src/llm/index.ts +9 -9
- package/src/llm/summarizer.ts +4 -4
- package/src/llm/wire.contracts.ts +1 -1
- package/src/mcp/effectors.ts +10 -10
- package/src/mcp/server.ts +11 -11
- package/src/pma/eval.ts +1 -1
- package/src/pma/index.ts +21 -21
- package/src/runners/outreach.runner.ts +3 -3
- package/src/runners/social.runner.ts +1 -1
- package/src/runners/thin-shim.runner.ts +1 -1
- package/src/sdk/will.ts +5 -5
- package/src/serve/server.ts +12 -12
- package/src/stem/assembly.audit.ts +3 -3
- package/src/stem/guards/identity.coherence.ts +10 -10
- package/src/stem/guards/identity.guard.ts +22 -22
- package/src/stem/index.ts +26 -11
- package/src/stem/mind.ts +12 -12
- package/src/stem/policy/arbiter.ts +136 -0
- package/src/stem/policy/rule.table.ts +172 -0
- package/src/stem/policy/verdict.recorder.ts +0 -0
- package/src/stem/tracts/biography.writer.ts +3 -3
- package/src/stem/tracts/effector.controller.ts +383 -4
- package/src/stem/tracts/health.reporter.ts +1 -1
- package/src/stem/tracts/outbox.controller.ts +4 -0
- package/src/stem/tracts/outbox.writer.ts +4 -4
- package/src/stem/tracts/pma.controller.ts +1 -1
- package/src/stem/tracts/replay.controller.ts +10 -10
- package/src/stem/tracts/sensory.controller.ts +2 -2
- package/src/stem/tracts/session.logger.ts +4 -4
- package/src/stem/tracts/transport/socketio.transport.ts +7 -7
- package/src/stem/tracts/transport/stream.transport.ts +2 -2
- package/src/stem/tracts/transport.controller.ts +15 -15
|
@@ -190,7 +190,7 @@ export class ExecutiveFacet {
|
|
|
190
190
|
this._onMasterSync
|
|
191
191
|
)
|
|
192
192
|
|
|
193
|
-
logger.info(
|
|
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(
|
|
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(
|
|
300
|
+
this._bus.unsubscribe(`executive-facet-${this.facetId}`)
|
|
301
301
|
this._listeners.clear()
|
|
302
302
|
|
|
303
|
-
logger.info(
|
|
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(
|
|
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(
|
|
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(
|
|
339
|
+
throw new Error(`[executive.facet] ${this.facetId} no state reference available`)
|
|
340
340
|
|
|
341
341
|
if( !this._currentFocus )
|
|
342
|
-
throw new Error(
|
|
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(
|
|
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(
|
|
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'
|
|
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(
|
|
399
|
-
stressLoad: currentState.metrics.get(
|
|
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(
|
|
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(
|
|
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(
|
|
623
|
+
catch( err ){ logger.error(`[executive.facet] ${this.facetId} listener error:`, err ) }
|
|
624
624
|
}
|
|
625
625
|
|
|
626
|
-
if( this._inbox ) this._inbox.enqueue(
|
|
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'
|
|
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'
|
|
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'
|
|
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 ?? ''
|
|
95
|
-
description: String( o.description ?? ''
|
|
96
|
-
upside: String( o.upside ?? ''
|
|
97
|
-
risk: String( o.risk ?? ''
|
|
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 === '{'
|
|
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'}`
|
|
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'
|
|
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(
|
|
297
|
-
if( stat.shiftDir > 0 ) quals.push(
|
|
298
|
-
else if( stat.shiftDir < 0 ) quals.push(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
649
|
+
const plansBlock = has('plans')
|
|
650
650
|
? this._buildActivePlansSection( context.plans, focus.awarenessEntityId, planRelevantIds ).trim()
|
|
651
651
|
: ''
|
|
652
652
|
|
|
653
|
-
const recentOutcomesBlock = has(
|
|
653
|
+
const recentOutcomesBlock = has('recentActions')
|
|
654
654
|
? this._buildRecentOutcomesSection( context.recentActions, state.tick ).trim()
|
|
655
655
|
: ''
|
|
656
656
|
|
|
657
|
-
const perceptsBlock = has(
|
|
658
|
-
? `## Percepts (What I Notice)\n${context.percepts.slice( 0, 10 ).map( p => `- [${p.category}] ${p.summary} (salience: ${p.salience.toFixed( 2 )})`
|
|
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(
|
|
667
|
+
).join('\n')}`
|
|
668
668
|
: ''
|
|
669
669
|
|
|
670
|
-
const ruminationsBlock = has(
|
|
671
|
-
? `## Active Ruminations (retrieved memories & thoughts)\n${context.workingMemory.map( w => `- [${w.type}] ${w.summary} (activation: ${w.activation.toFixed( 2 )})`
|
|
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(
|
|
674
|
+
const memoriesBlock = has('memories')
|
|
675
675
|
? this._buildMemoriesSection( context.memories, state.tick )
|
|
676
676
|
: ''
|
|
677
677
|
|
|
678
|
-
const beliefsBlock = has(
|
|
679
|
-
? `## My Beliefs\n${context.beliefs.map( b => `- [${b.category}] ${b.statement} (confidence: ${( b.confidence * 100 ).toFixed( 0 )}%)`
|
|
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(
|
|
689
|
-
if( s.emotion ) bits.push(
|
|
690
|
-
if( s.trust != null ) bits.push(
|
|
691
|
-
if( s.reliability != null && s.reliability !== 0.5 ) bits.push(
|
|
692
|
-
if( s.closeness != null && s.closeness > 0.1 ) bits.push(
|
|
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(
|
|
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(
|
|
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'
|
|
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(
|
|
805
|
-
const stressZone = state.metrics.get(
|
|
806
|
-
const cognitivePhase = state.metrics.get(
|
|
807
|
-
const energyDegradation = state.metrics.get(
|
|
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(
|
|
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'
|
|
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'
|
|
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}`
|
|
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(
|
|
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(
|
|
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(
|
|
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'
|
|
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 ?? ''
|
|
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(
|
|
1066
|
-
if( styleGeneric ) hints.push(
|
|
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(
|
|
1068
|
+
return `\n\n## 💡 Identity Reflection (every ${NUDGE_INTERVAL} ticks)\n${hints.join('\n')}`
|
|
1069
1069
|
}
|
|
1070
1070
|
}
|
|
1071
1071
|
|