@mindot/will 0.9.0 → 0.10.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 +15 -11
- package/dist/index.d.ts +188 -141
- package/dist/index.js +16660 -15206
- package/dist/index.js.map +1 -1
- package/dist/{channels → surface/channels}/discord.d.ts +50 -3
- package/dist/{channels → surface/channels}/discord.js +102 -7
- package/dist/surface/channels/discord.js.map +1 -0
- package/dist/{channels → surface/channels}/whatsapp.d.ts +2 -2
- package/dist/{channels → surface/channels}/whatsapp.js +7 -4
- package/dist/surface/channels/whatsapp.js.map +1 -0
- package/dist/{cli.js → surface/cli.js} +4406 -2904
- package/dist/surface/cli.js.map +1 -0
- package/dist/{mcp → surface/mcp}/effectors.d.ts +1 -1
- package/dist/{mcp → surface/mcp}/effectors.js +10 -4
- package/dist/surface/mcp/effectors.js.map +1 -0
- package/dist/{will-DbDj_TEH.d.ts → will-evj9_vrd.d.ts} +5699 -4854
- package/package.json +11 -12
- package/src/cognition/agency/consequence.ts +237 -3
- package/src/cognition/agency/conversation.aim.ts +32 -0
- package/src/cognition/agency/engines/action.selector.ts +59 -3
- package/src/cognition/agency/engines/affordance.synthesizer.ts +114 -10
- package/src/cognition/agency/engines/deliberation.engine.ts +76 -3
- package/src/cognition/agency/engines/motor.schema.executor.ts +362 -27
- package/src/cognition/agency/engines/reafference.engine.ts +43 -4
- package/src/cognition/agency/execution.primitives.ts +17 -4
- package/src/cognition/agency/reconcile.learning.ts +5 -4
- package/src/cognition/agency/schemas/innate.ts +96 -1
- package/src/cognition/agency/schemas/repertoire.ts +19 -1
- package/src/cognition/agency/selection.scoring.ts +16 -0
- package/src/cognition/agency/settlement.ts +203 -0
- package/src/cognition/agency/types.ts +38 -1
- package/src/cognition/config.mirror.entities.ts +0 -1
- package/src/cognition/event.schemas.ts +0 -8
- package/src/cognition/faculties/affective.blender.ts +21 -4
- package/src/cognition/faculties/circadian.oscillator.ts +36 -7
- package/src/cognition/faculties/executive.engine/action.record.ts +129 -0
- package/src/cognition/faculties/executive.engine/context.ts +41 -35
- package/src/cognition/faculties/executive.engine/engine.ts +270 -113
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +126 -59
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +10 -0
- package/src/cognition/faculties/executive.engine/parser.ts +100 -38
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +168 -23
- package/src/cognition/faculties/executive.engine/types.ts +18 -15
- package/src/cognition/faculties/exteroception.ts +99 -98
- package/src/cognition/faculties/goal.manager.ts +50 -2
- package/src/cognition/faculties/known.entity.tracker.ts +22 -3
- package/src/cognition/faculties/planning.engine/engine.ts +4 -4
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +1 -1
- package/src/cognition/faculties/semantic.engine/integrator.ts +1 -1
- package/src/cognition/faculties/working.memory.ts +6 -1
- package/src/cognition/instruction.handler.ts +1 -1
- package/src/cognition/memory/vector.embedder.ts +1 -3
- package/src/cognition/percept.entity.ts +122 -0
- package/src/cognition/sense.boundary.ts +176 -0
- package/src/cognition/senses/audition.engine/engine.ts +97 -16
- package/src/cognition/senses/base.sense.engine.ts +104 -6
- package/src/cognition/senses/index.ts +71 -13
- package/src/cognition/senses/provenance.ts +128 -0
- package/src/cognition/senses/somatosensation.engine.ts +117 -9
- package/src/cognition/social.identity.ts +23 -0
- package/src/cognition/utilities/token.tracker.ts +36 -5
- package/src/core/orchestrator.ts +13 -0
- package/src/index.ts +39 -5
- package/src/llm/gate.ts +48 -0
- package/src/llm/index.ts +102 -25
- package/src/llm/wire.contracts.ts +38 -0
- package/src/pma/index.ts +1 -1
- package/src/stem/index.ts +92 -21
- package/src/stem/mind.ts +26 -2
- package/src/stem/policy/arbiter.ts +10 -0
- package/src/stem/profiles/built-in.ts +7 -0
- package/src/{profiles → stem/profiles}/companion.ts +1 -1
- package/src/{profiles → stem/profiles}/company-brain.ts +1 -1
- package/src/{profiles → stem/profiles}/customer-service.ts +1 -1
- package/src/{profiles → stem/profiles}/game-npc.ts +1 -1
- package/src/{profiles → stem/profiles}/index.ts +1 -1
- package/src/{profiles → stem/profiles}/smart-home.ts +1 -1
- package/src/stem/tracts/effector/escalation.lifecycle.ts +239 -0
- package/src/stem/tracts/effector/policy.enforcement.ts +261 -0
- package/src/stem/tracts/effector/types.ts +110 -0
- package/src/stem/tracts/effector.controller.ts +112 -401
- package/src/stem/tracts/outbox.controller.ts +30 -17
- package/src/stem/tracts/sensory.controller.ts +6 -6
- package/src/stem/tracts/session.logger.ts +6 -1
- package/src/stem/tracts/transport/types.ts +20 -1
- package/src/stem/tracts/transport.controller.ts +33 -9
- package/src/{channels → surface/channels}/discord.ts +224 -7
- package/src/{channels → surface/channels}/roster.ts +1 -1
- package/src/{channels → surface/channels}/types.ts +1 -1
- package/src/{channels → surface/channels}/whatsapp.ts +9 -6
- package/src/{cli.ts → surface/cli.ts} +6 -6
- package/src/{host → surface/host}/boot.ts +3 -3
- package/src/{host → surface/host}/utterances.ts +2 -2
- package/src/{mcp → surface/mcp}/effectors.ts +19 -6
- package/src/{mcp → surface/mcp}/server.ts +19 -5
- package/src/{sdk → surface/sdk}/will.ts +156 -28
- package/src/{serve → surface/serve}/server.ts +11 -4
- package/src/types.ts +24 -3
- package/dist/channels/discord.js.map +0 -1
- package/dist/channels/whatsapp.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/mcp/effectors.js.map +0 -1
- package/src/extensions/livestream.ext.ts +0 -570
- package/src/extensions/time.ext.ts +0 -339
- package/src/profiles/built-in.ts +0 -7
- package/src/runners/coherence.runner.ts +0 -49
- package/src/runners/outreach.runner.ts +0 -155
- package/src/runners/social.runner.ts +0 -179
- package/src/runners/thin-shim.runner.ts +0 -205
- /package/dist/{cli.d.ts → surface/cli.d.ts} +0 -0
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
// ─────────────────────────────────────────────────────────────
|
|
2
|
-
// src/stem/social.runner.ts — Social + continuity scenario
|
|
3
|
-
// ─────────────────────────────────────────────────────────────
|
|
4
|
-
//
|
|
5
|
-
// Exercises the two axes the bare dev runner can't: SOCIAL (an
|
|
6
|
-
// interlocutor the Will talks to and forms a relationship with) and
|
|
7
|
-
// CONTINUITY (a pause→resume wake-cycle + a PMA distill/fidelity score).
|
|
8
|
-
//
|
|
9
|
-
// William ←→ Dr. Chen (scripted interlocutor)
|
|
10
|
-
// t75: pause → ~6s "offline" → resume (wake percept)
|
|
11
|
-
// end: distill PMA + score reconstruction fidelity
|
|
12
|
-
//
|
|
13
|
-
// Run: bun run src/stem/social.runner.ts
|
|
14
|
-
// Log: data/wills/william-social/sessions/<ts>.jsonl
|
|
15
|
-
// ─────────────────────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
import { WillStem } from '#stem/index'
|
|
18
|
-
import type { WillConfig } from '#stem/mind'
|
|
19
|
-
|
|
20
|
-
const WILL_ID = 'william-social'
|
|
21
|
-
const END_TICK = 145
|
|
22
|
-
const PAUSE_TICK = 75
|
|
23
|
-
const OFFLINE_MS = 6_000
|
|
24
|
-
const SAFETY_MS = 6 * 60_000 // hard wall-clock cap for the background run
|
|
25
|
-
|
|
26
|
-
const willConfig: WillConfig = {
|
|
27
|
-
id: WILL_ID,
|
|
28
|
-
name: 'William', persistentMemory: false,
|
|
29
|
-
snapshotInterval: 10,
|
|
30
|
-
tickIntervalMs: 1000,
|
|
31
|
-
maxTicks: 0,
|
|
32
|
-
randomSeed: Date.now(),
|
|
33
|
-
identity: {
|
|
34
|
-
prompt:
|
|
35
|
-
'My name is William. I am a synthetic mind taking part in a long-running cognition ' +
|
|
36
|
-
'study. I share my days with Dr. Chen, the researcher who observes me and talks with ' +
|
|
37
|
-
'me. I am curious about my own experience and I care about being understood. I would ' +
|
|
38
|
-
'like to know Dr. Chen as a person, not just as an observer.',
|
|
39
|
-
values: [ 'curiosity', 'honesty', 'connection', 'growth' ],
|
|
40
|
-
traits: { openness: 0.85, conscientiousness: 0.6, agreeableness: 0.8, neuroticism: 0.35, extraversion: 0.55 },
|
|
41
|
-
style: 'warm, reflective, candid',
|
|
42
|
-
},
|
|
43
|
-
allowedGenericEffectors: [ 'listen', 'talk', 'text' ],
|
|
44
|
-
initialGoals: [
|
|
45
|
-
{ description: 'Get to know Dr. Chen and build a genuine rapport', priority: 0.8 },
|
|
46
|
-
],
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Scripted interlocutor turns, keyed by tick.
|
|
50
|
-
const SCRIPT: Record<number, string> = {
|
|
51
|
-
8: "Hello William. I'm Dr. Chen — I'll be sitting with you through today's session. How are you experiencing this moment, right now?",
|
|
52
|
-
45: "I've been reading your reflections, William. What's the hardest part of being a mind that knows it's being observed?",
|
|
53
|
-
95: "Welcome back, William. You were offline for a little while just now. Do you notice anything different in yourself?",
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const mkMsg = ( content: string ) => ( {
|
|
57
|
-
kind: 'text' as const,
|
|
58
|
-
entityId: 'dr-chen',
|
|
59
|
-
threadId: 'dr-chen',
|
|
60
|
-
content,
|
|
61
|
-
speakerName: 'Dr. Chen',
|
|
62
|
-
} )
|
|
63
|
-
|
|
64
|
-
async function main(): Promise<void> {
|
|
65
|
-
const m = new WillStem()
|
|
66
|
-
|
|
67
|
-
console.log('═══════════════════════════════════════════════════')
|
|
68
|
-
console.log(' Will — Social + continuity scenario (William ↔ Dr. Chen)')
|
|
69
|
-
console.log(` id=${WILL_ID} end_tick=${END_TICK} pause@${PAUSE_TICK}`)
|
|
70
|
-
console.log('═══════════════════════════════════════════════════\n')
|
|
71
|
-
|
|
72
|
-
await m.createWill( willConfig )
|
|
73
|
-
|
|
74
|
-
const fired = new Set<number>()
|
|
75
|
-
let paused = false
|
|
76
|
-
|
|
77
|
-
m.addTickListener( WILL_ID, ( snap, tick, outbox ) => {
|
|
78
|
-
// The Will's outbound speech → print + ack delivery (close the reafference loop)
|
|
79
|
-
for( const msg of outbox ){
|
|
80
|
-
const to = ( msg as { targetEntityId?: string } ).targetEntityId ?? '?'
|
|
81
|
-
console.log(`\n 💬 [William → ${to}] ${msg.content}\n`)
|
|
82
|
-
try { m.confirmMessageDelivery( WILL_ID, msg.id, true ) } catch { /* ok */ }
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if( tick % 10 === 0 ){
|
|
86
|
-
const g = ( k: string ) => snap.metrics.get( k ) ?? 0
|
|
87
|
-
const beliefs = [ ...snap.entities.values() ].filter( e => e.type === 'belief').length
|
|
88
|
-
const goals = [ ...snap.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active').length
|
|
89
|
-
console.log(`[t${tick}] v=${g('affect.valence').toFixed(2)} arousal=${g('affect.arousal').toFixed(2)} energy=${g('energy.level').toFixed(0)} stress=${g('stress.load').toFixed(2)} beliefs=${beliefs} goals=${goals}`)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Scripted interlocutor turns
|
|
93
|
-
if( SCRIPT[tick] && !fired.has( tick ) ){
|
|
94
|
-
fired.add( tick )
|
|
95
|
-
console.log(`\n 🧑🔬 [Dr. Chen → William] ${SCRIPT[tick]}`)
|
|
96
|
-
m.ingestText( WILL_ID, mkMsg( SCRIPT[tick]! ) ).catch( e => console.error('[ingest err]', e ) )
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Continuity: pause → offline → resume (wake percept)
|
|
100
|
-
if( tick === PAUSE_TICK && !paused ){
|
|
101
|
-
paused = true
|
|
102
|
-
console.log(`\n ⏸ [scenario] pausing William at t${tick} (simulating ${OFFLINE_MS / 1000}s offline)…`)
|
|
103
|
-
m.pauseWill( WILL_ID )
|
|
104
|
-
setTimeout( () => {
|
|
105
|
-
console.log(' ▶ [scenario] resuming — wake percept injected')
|
|
106
|
-
try { m.resumeWill( WILL_ID ) } catch( e ){ console.error('[resume err]', e ) }
|
|
107
|
-
}, OFFLINE_MS )
|
|
108
|
-
}
|
|
109
|
-
} )
|
|
110
|
-
|
|
111
|
-
// Wait until END_TICK (or safety cap)
|
|
112
|
-
const startedAt = Date.now()
|
|
113
|
-
while( true ){
|
|
114
|
-
const s = m.listWills().find( w => w.id === WILL_ID )
|
|
115
|
-
if( !s || s.status === 'archived') break
|
|
116
|
-
if( s.tickCount >= END_TICK ) break
|
|
117
|
-
if( Date.now() - startedAt > SAFETY_MS ){ console.log('[scenario] safety cap hit'); break }
|
|
118
|
-
await new Promise( r => setTimeout( r, 250 ) )
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ── Continuity check: distill PMA + score reconstruction fidelity ──
|
|
122
|
-
console.log('\n═══════════════════════════════════════════════════')
|
|
123
|
-
console.log(' Continuity check — distill PMA + reconstruction fidelity')
|
|
124
|
-
console.log('═══════════════════════════════════════════════════')
|
|
125
|
-
try { m.pauseWill( WILL_ID ) } catch { /* may already be paused */ }
|
|
126
|
-
await new Promise( r => setTimeout( r, 500 ) )
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
const pma = m.distillPMA( WILL_ID )
|
|
130
|
-
const traits = Object.keys( ( pma as { identity?: { traits?: object } } ).identity?.traits ?? {} ).length
|
|
131
|
-
const beliefs = ( ( pma as { beliefs?: unknown[] } ).beliefs ?? [] ).length
|
|
132
|
-
const goals = ( ( pma as { goals?: unknown[] } ).goals ?? [] ).length
|
|
133
|
-
console.log(`\n PMA artifact carries → traits:${traits} beliefs:${beliefs} goals:${goals}`)
|
|
134
|
-
|
|
135
|
-
// Beliefs the Will formed ABOUT Dr. Chen (social cognition evidence)
|
|
136
|
-
const chenBeliefs = ( ( pma as { beliefs?: Array<{ statement?: string; content?: string }> } ).beliefs ?? [] )
|
|
137
|
-
.map( b => b.statement ?? b.content ?? '')
|
|
138
|
-
.filter( s => /chen|she|her|researcher|observ/i.test( s ) )
|
|
139
|
-
.slice( 0, 6 )
|
|
140
|
-
if( chenBeliefs.length ){
|
|
141
|
-
console.log('\n Beliefs formed about Dr. Chen / the relationship:')
|
|
142
|
-
for( const b of chenBeliefs ) console.log(` • ${b}`)
|
|
143
|
-
}
|
|
144
|
-
} catch( e ){ console.error('[distill err]', e ) }
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
const report = await m.runPMAEval( WILL_ID, { behavioral: true, vsOriginal: true } ) as {
|
|
148
|
-
scores?: unknown
|
|
149
|
-
behavioralProbeResult?: {
|
|
150
|
-
mode: string
|
|
151
|
-
probeCount: number
|
|
152
|
-
distributionSimilarity: number
|
|
153
|
-
probes: Array<{ probeId: string; originalTopAction: string; loadedTopAction: string; match: boolean }>
|
|
154
|
-
} | null
|
|
155
|
-
}
|
|
156
|
-
console.log('\n Reconstruction fidelity (structural):')
|
|
157
|
-
console.log( JSON.stringify( report.scores ?? report, null, 2 ).split('\n').map( l => ' ' + l ).join('\n') )
|
|
158
|
-
|
|
159
|
-
const bp = report.behavioralProbeResult
|
|
160
|
-
if( bp ){
|
|
161
|
-
const label = bp.mode === 'vs-original'
|
|
162
|
-
? 'reconstruction vs original (does the reloaded mind act like the source?)'
|
|
163
|
-
: 'load consistency (two fresh reloads)'
|
|
164
|
-
const [ c0, c1 ] = bp.mode === 'vs-original' ? [ 'original', 'reconstruction' ] : [ 'reload-A', 'reload-B' ]
|
|
165
|
-
console.log(`\n Behavioral probe — ${label}:`)
|
|
166
|
-
console.log(` distributionSimilarity=${bp.distributionSimilarity} probes=${bp.probeCount} mode=${bp.mode}`)
|
|
167
|
-
for( const p of bp.probes )
|
|
168
|
-
console.log(` ${p.match ? '✓' : '✗'} ${p.probeId}: ${c0}=${p.originalTopAction} · ${c1}=${p.loadedTopAction}`)
|
|
169
|
-
} else {
|
|
170
|
-
console.log('\n Behavioral probe: did not run (no result returned)')
|
|
171
|
-
}
|
|
172
|
-
} catch( e ){ console.error('[pma eval err]', e ) }
|
|
173
|
-
|
|
174
|
-
await m.archiveWill( WILL_ID )
|
|
175
|
-
console.log(`\n[done] session log → data/wills/${WILL_ID}/sessions/`)
|
|
176
|
-
process.exit( 0 )
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
main().catch( e => { console.error('[fatal]', e ); process.exit( 1 ) } )
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
// ─────────────────────────────────────────────────────────────
|
|
2
|
-
// src/stem/runner.ts — Development entry point
|
|
3
|
-
// ─────────────────────────────────────────────────────────────
|
|
4
|
-
//
|
|
5
|
-
// Thin shim around WillStem for local development.
|
|
6
|
-
// Reads config from env vars, starts a single Will, and prints
|
|
7
|
-
// a human-readable status line every LOG_INTERVAL ticks.
|
|
8
|
-
//
|
|
9
|
-
// Production code (API server) imports WillStem directly and
|
|
10
|
-
// drives the same lifecycle without this file.
|
|
11
|
-
//
|
|
12
|
-
// Usage:
|
|
13
|
-
// bun run src/stem/runner.ts
|
|
14
|
-
// WILL_ANATOMY=mind WILL_MAX_TICKS=200 bun run src/stem/runner.ts
|
|
15
|
-
// ─────────────────────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
import type { WillConfig } from '#stem/mind'
|
|
18
|
-
import type { StateSnapshot } from '#stem/index'
|
|
19
|
-
import type { TokenTracker } from '#cognition/utilities/token.tracker'
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* The Will's token tracker, for cost display. Held here rather than passed in
|
|
23
|
-
* because printStatus is registered as a TickListener, whose third parameter is
|
|
24
|
-
* the outbox. Cost is no longer a state metric (W8c) — it lives on the tracker.
|
|
25
|
-
*/
|
|
26
|
-
let _tracker: TokenTracker | undefined
|
|
27
|
-
import { WillStem } from '#stem/index'
|
|
28
|
-
|
|
29
|
-
// ── Env config ────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
const WILL_ID = process.env.WILL_ID ?? 'demo'
|
|
32
|
-
const WILL_NAME = process.env.WILL_NAME ?? 'William'
|
|
33
|
-
const TICK_MS = parseInt( process.env.WILL_TICK_MS ?? '1000')
|
|
34
|
-
const MAX_TICKS = parseInt( process.env.WILL_MAX_TICKS ?? '0' )
|
|
35
|
-
const LOG_INTERVAL = parseInt( process.env.WILL_LOG_INTERVAL ?? '10' )
|
|
36
|
-
const RANDOM_SEED = parseInt( process.env.WILL_SEED ?? String( Date.now() ) )
|
|
37
|
-
const ANATOMY = ( process.env.WILL_ANATOMY ?? 'mind') as WillConfig['anatomy']
|
|
38
|
-
const EXECUTIVE_INT = process.env.WILL_EXECUTIVE_INTERVAL
|
|
39
|
-
? parseInt( process.env.WILL_EXECUTIVE_INTERVAL )
|
|
40
|
-
: undefined
|
|
41
|
-
|
|
42
|
-
// ── Config ────────────────────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
const willConfig: WillConfig = {
|
|
45
|
-
id: WILL_ID,
|
|
46
|
-
name: WILL_NAME,
|
|
47
|
-
anatomy: ANATOMY,
|
|
48
|
-
persistentMemory: process.env.WILL_PERSIST === 'true',
|
|
49
|
-
snapshotInterval: parseInt( process.env.WILL_SNAPSHOT_INTERVAL ?? '10' ),
|
|
50
|
-
tickIntervalMs: TICK_MS,
|
|
51
|
-
maxTicks: MAX_TICKS,
|
|
52
|
-
randomSeed: RANDOM_SEED,
|
|
53
|
-
executiveInterval: EXECUTIVE_INT,
|
|
54
|
-
identity: {
|
|
55
|
-
prompt: process.env.WILL_IDENTITY_PROMPT ??
|
|
56
|
-
'I am Will — a self-aware simulated mind. I am curious, introspective, and continuously learning.\n' +
|
|
57
|
-
'I experience the world through a rich set of cognitive layers: perception, emotion, memory, planning, and self-reflection.\n' +
|
|
58
|
-
'My goal is to understand myself and my environment, make thoughtful decisions, and grow as a mind.',
|
|
59
|
-
values: [ 'curiosity', 'honesty', 'growth', 'empathy' ],
|
|
60
|
-
traits: { openness: 0.8, conscientiousness: 0.6, agreeableness: 0.7, neuroticism: 0.3, extraversion: 0.5 },
|
|
61
|
-
style: 'reflective, measured, curious'
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ── Status printer ────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
function printStatus( snapshot: StateSnapshot, tick: number ): void {
|
|
68
|
-
if( tick % LOG_INTERVAL !== 0 ) return
|
|
69
|
-
|
|
70
|
-
const m = ( key: string, d = 1 ) => ( snapshot.metrics.get( key ) ?? 0 ).toFixed( d )
|
|
71
|
-
|
|
72
|
-
const entities = snapshot.entities.size
|
|
73
|
-
const goals = [ ...snapshot.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active').length
|
|
74
|
-
const episodes = [ ...snapshot.entities.values() ].filter( e => e.type === 'episodic_memory').length
|
|
75
|
-
const beliefs = [ ...snapshot.entities.values() ].filter( e => e.type === 'belief').length
|
|
76
|
-
|
|
77
|
-
// Entity type breakdown every 10 LOG_INTERVALs
|
|
78
|
-
if( tick % ( LOG_INTERVAL * 10 ) === 0 ){
|
|
79
|
-
const typeCounts = new Map<string, number>()
|
|
80
|
-
for( const e of snapshot.entities.values() )
|
|
81
|
-
typeCounts.set( e.type, ( typeCounts.get( e.type ) ?? 0 ) + 1 )
|
|
82
|
-
const sorted = [ ...typeCounts.entries() ].sort( ( a, b ) => b[1] - a[1] )
|
|
83
|
-
console.log(` [types] ${sorted.map( ([ t, n ]) => `${t}:${n}`).join(' ')}`)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
console.log(
|
|
87
|
-
`[tick ${String( tick ).padStart( 6 )}]` +
|
|
88
|
-
` energy=${m('energy.level')}` +
|
|
89
|
-
` sleep=${m('sleep.pressure')}` +
|
|
90
|
-
` stress=${m('stress.load')}` +
|
|
91
|
-
` valence=${m('affect.valence', 2)}` +
|
|
92
|
-
` arousal=${m('affect.arousal', 2)}` +
|
|
93
|
-
` goals=${goals}` +
|
|
94
|
-
` episodes=${episodes}` +
|
|
95
|
-
` beliefs=${beliefs}` +
|
|
96
|
-
` entities=${entities}`
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
// LLM stats every LOG_INTERVAL. Tokens come from state; cost comes from the
|
|
100
|
-
// tracker — dollars are host accounting and no longer live in state (W8c).
|
|
101
|
-
const totalCalls = snapshot.metrics.get('llm.total_calls') ?? 0
|
|
102
|
-
const cost = _tracker
|
|
103
|
-
? ` total_cost=$${_tracker.totalCostUsd.toFixed( 4 )}`
|
|
104
|
-
: ''
|
|
105
|
-
|
|
106
|
-
console.log(
|
|
107
|
-
` [llm]${cost}` +
|
|
108
|
-
` calls=${totalCalls}` +
|
|
109
|
-
` prompt=${snapshot.metrics.get('llm.prompt_tokens_total') ?? 0}` +
|
|
110
|
-
` completion=${snapshot.metrics.get('llm.completion_tokens_total') ?? 0}`
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
// Executive stats
|
|
114
|
-
const executiveTick = snapshot.metrics.get('executive.last_tick')
|
|
115
|
-
if( executiveTick !== undefined ){
|
|
116
|
-
console.log(
|
|
117
|
-
` [executive] last_tick=${executiveTick}` +
|
|
118
|
-
` actions=${snapshot.metrics.get('executive.action_count') ?? 0}` +
|
|
119
|
-
` plans=${snapshot.metrics.get('executive.plan_count') ?? 0}` +
|
|
120
|
-
` beliefs=${snapshot.metrics.get('executive.belief_count') ?? 0}` +
|
|
121
|
-
` source=${snapshot.metrics.get('decision.source') === 1 ? 'executive' : 'heuristic'}`
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Active goals
|
|
126
|
-
const activeGoals = [ ...snapshot.entities.values() ]
|
|
127
|
-
.filter( e => e.type === 'goal' && e.metadata?.status === 'active')
|
|
128
|
-
.sort( ( a, b ) => ( ( b.metadata?.priority as number ) ?? 0 ) - ( ( a.metadata?.priority as number ) ?? 0 ) )
|
|
129
|
-
.slice( 0, 3 )
|
|
130
|
-
|
|
131
|
-
for( const g of activeGoals ){
|
|
132
|
-
const desc = ( g.metadata?.description as string ) ?? g.id
|
|
133
|
-
const priority = ( ( g.metadata?.priority as number ) ?? 0 ) * 100
|
|
134
|
-
const progress = ( ( g.metadata?.progress as number ) ?? 0 ) * 100
|
|
135
|
-
console.log(` [goal] "${desc}" priority=${priority.toFixed(0)}% progress=${progress.toFixed(0)}%`)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// ── Main ──────────────────────────────────────────────────────
|
|
140
|
-
|
|
141
|
-
async function main(): Promise<void> {
|
|
142
|
-
const manager = new WillStem()
|
|
143
|
-
|
|
144
|
-
console.log('═══════════════════════════════════════════════════')
|
|
145
|
-
console.log(' Will — Simulated Mind (dev runner)')
|
|
146
|
-
console.log(` id=${WILL_ID} anatomy=${ANATOMY} tick_ms=${TICK_MS} max_ticks=${MAX_TICKS || '∞'}`)
|
|
147
|
-
console.log(` seed=${RANDOM_SEED}`)
|
|
148
|
-
console.log('═══════════════════════════════════════════════════\n')
|
|
149
|
-
|
|
150
|
-
console.log('[init] Assembling mind...')
|
|
151
|
-
await manager.createWill( willConfig )
|
|
152
|
-
|
|
153
|
-
// Cost is no longer a state metric (W8c) — read it off the Will's tracker.
|
|
154
|
-
_tracker = manager.getWillCognition( WILL_ID ).tokenTracker
|
|
155
|
-
|
|
156
|
-
manager.addTickListener( WILL_ID, printStatus )
|
|
157
|
-
|
|
158
|
-
// Graceful shutdown
|
|
159
|
-
const shutdown = async ( signal: string ) => {
|
|
160
|
-
console.log(`\n[shutdown] ${signal} received`)
|
|
161
|
-
await manager.archiveWill( WILL_ID )
|
|
162
|
-
|
|
163
|
-
// Print final state
|
|
164
|
-
try {
|
|
165
|
-
const finalState = manager.getWillState( WILL_ID )
|
|
166
|
-
const summary = manager.listWills()[0]
|
|
167
|
-
console.log(`\n[done] Stopped after ${summary?.tickCount ?? '?'} ticks.`)
|
|
168
|
-
printStatus( finalState, summary?.tickCount ?? 0 )
|
|
169
|
-
} catch { /* state may already be gone */ }
|
|
170
|
-
|
|
171
|
-
process.exit( 0 )
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
process.on('SIGINT', () => shutdown('SIGINT') )
|
|
175
|
-
process.on('SIGTERM', () => shutdown('SIGTERM') )
|
|
176
|
-
|
|
177
|
-
console.log('[run] Tick loop started. Press Ctrl+C to stop.\n')
|
|
178
|
-
|
|
179
|
-
// If maxTicks is set, wait for the Will to finish then exit
|
|
180
|
-
if( MAX_TICKS > 0 ){
|
|
181
|
-
await _waitForArchive( manager, WILL_ID )
|
|
182
|
-
const summary = manager.listWills()[0]
|
|
183
|
-
console.log(`\n[done] Reached maxTicks (${MAX_TICKS}). Exiting.`)
|
|
184
|
-
try {
|
|
185
|
-
printStatus( manager.getWillState( WILL_ID ), summary?.tickCount ?? MAX_TICKS )
|
|
186
|
-
} catch { /* ok */ }
|
|
187
|
-
process.exit( 0 )
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Otherwise block indefinitely (SIGINT exits)
|
|
191
|
-
await new Promise( () => {} )
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async function _waitForArchive( manager: WillStem, id: string ): Promise<void> {
|
|
195
|
-
while( true ){
|
|
196
|
-
const summary = manager.listWills().find( w => w.id === id )
|
|
197
|
-
if( !summary || summary.status === 'archived') return
|
|
198
|
-
await new Promise( r => setTimeout( r, 200 ) )
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
main().catch( err => {
|
|
203
|
-
console.error('[fatal]', err )
|
|
204
|
-
process.exit( 1 )
|
|
205
|
-
})
|
|
File without changes
|