@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
|
@@ -167,7 +167,7 @@ export class SelfModelUpdater extends AsyncEngine implements CognitiveEngine {
|
|
|
167
167
|
case 'executive.prediction.formed': {
|
|
168
168
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
169
169
|
if( p.predictedDomains.includes('metacognition') )
|
|
170
|
-
this._model.setPrecision(
|
|
170
|
+
this._model.setPrecision('self_model.change', 1.0 + p.confidence * 0.5 )
|
|
171
171
|
|
|
172
172
|
break
|
|
173
173
|
}
|
|
@@ -196,13 +196,13 @@ export class SelfModelUpdater extends AsyncEngine implements CognitiveEngine {
|
|
|
196
196
|
restore( snap: Record<string, unknown> ): void {
|
|
197
197
|
if( !snap ) return
|
|
198
198
|
|
|
199
|
-
if( typeof snap.executiveReflectionTick === 'number'
|
|
199
|
+
if( typeof snap.executiveReflectionTick === 'number')
|
|
200
200
|
this._executiveReflectionTick = snap.executiveReflectionTick
|
|
201
201
|
|
|
202
|
-
if( typeof snap.lastEvaluationTick === 'number'
|
|
202
|
+
if( typeof snap.lastEvaluationTick === 'number')
|
|
203
203
|
this._lastEvaluationTick = snap.lastEvaluationTick
|
|
204
204
|
|
|
205
|
-
if( typeof snap.experienceCountAtLastEval === 'number'
|
|
205
|
+
if( typeof snap.experienceCountAtLastEval === 'number')
|
|
206
206
|
this._experienceCountAtLastEval = snap.experienceCountAtLastEval
|
|
207
207
|
|
|
208
208
|
if( Array.isArray( snap.domainPerformance ) )
|
|
@@ -231,7 +231,7 @@ export class SelfModelUpdater extends AsyncEngine implements CognitiveEngine {
|
|
|
231
231
|
// closed edge of the metacognition cycle: a learned prior (written back by
|
|
232
232
|
// the consolidator from the Will's own introspection) modulates how often
|
|
233
233
|
// the self-model re-evaluates, without ever mutating the seeded base.
|
|
234
|
-
const p = readEffectiveParams( state, 'engine-config-self-model'
|
|
234
|
+
const p = readEffectiveParams( state, 'engine-config-self-model')
|
|
235
235
|
|
|
236
236
|
if( p.minIntervalTicks != null ) this._minIntervalTicks = p.minIntervalTicks
|
|
237
237
|
if( p.minNewExperiences != null ) this._minNewExperiences = p.minNewExperiences
|
|
@@ -483,7 +483,7 @@ export class SelfModelUpdater extends AsyncEngine implements CognitiveEngine {
|
|
|
483
483
|
supportingEpisodes: da.sampleSize,
|
|
484
484
|
lastUpdatedAt: tick,
|
|
485
485
|
tags: [ da.domain, 'competence', 'self', 'positive' ]
|
|
486
|
-
}, tick, 'self-model'
|
|
486
|
+
}, tick, 'self-model')
|
|
487
487
|
|
|
488
488
|
else if( da.successRate < 0.30 )
|
|
489
489
|
this._semanticIntegrator.integrateExecutiveBelief({
|
|
@@ -494,14 +494,14 @@ export class SelfModelUpdater extends AsyncEngine implements CognitiveEngine {
|
|
|
494
494
|
supportingEpisodes: da.sampleSize,
|
|
495
495
|
lastUpdatedAt: tick,
|
|
496
496
|
tags: [ da.domain, 'competence', 'self', 'negative' ]
|
|
497
|
-
}, tick, 'self-model'
|
|
497
|
+
}, tick, 'self-model')
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
502
502
|
const _bus = this._bus
|
|
503
503
|
if( _bus ){
|
|
504
|
-
const predErr = this._model.observe(
|
|
504
|
+
const predErr = this._model.observe('self_model.change', changeMagnitude )
|
|
505
505
|
if( !predErr.gated )
|
|
506
506
|
_bus.publish({
|
|
507
507
|
type: 'self_model.updated',
|
|
@@ -87,7 +87,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
87
87
|
* Confidence is capped by evidence count before integration — prevents the
|
|
88
88
|
* executive from asserting high-certainty beliefs from thin episodic support.
|
|
89
89
|
*/
|
|
90
|
-
integrateExecutiveBelief( belief: Belief, tick?: number, cause = 'executive'
|
|
90
|
+
integrateExecutiveBelief( belief: Belief, tick?: number, cause = 'executive'): void {
|
|
91
91
|
const capped = this._capConfidenceByEvidence( belief.confidence, belief.supportingEpisodes )
|
|
92
92
|
const result = this._integrateBelief({ ...belief, confidence: capped }, cause )
|
|
93
93
|
|
|
@@ -118,7 +118,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
118
118
|
*/
|
|
119
119
|
private _restoreFromState( state: ReadonlySimulationState ): void {
|
|
120
120
|
for( const entity of state.entities.values() ){
|
|
121
|
-
if( entity.type !== 'belief'
|
|
121
|
+
if( entity.type !== 'belief') continue
|
|
122
122
|
if( this._beliefs.some( b => b.id === entity.id ) ) continue
|
|
123
123
|
|
|
124
124
|
const m = entity.metadata ?? {}
|
|
@@ -160,7 +160,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
160
160
|
case 'executive.prediction.formed': {
|
|
161
161
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
162
162
|
if( p.predictedDomains.includes('memory') )
|
|
163
|
-
this._model.setPrecision(
|
|
163
|
+
this._model.setPrecision('belief.count', 1.0 + p.confidence * 0.5 )
|
|
164
164
|
|
|
165
165
|
break
|
|
166
166
|
}
|
|
@@ -201,7 +201,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
201
201
|
if( payload.knownEntityUpdates )
|
|
202
202
|
for( const u of payload.knownEntityUpdates )
|
|
203
203
|
for( const fact of u.learned ?? [] )
|
|
204
|
-
if( fact && u.keid && u.keid !== 'agent-self'
|
|
204
|
+
if( fact && u.keid && u.keid !== 'agent-self')
|
|
205
205
|
this.integrateExecutiveBelief({
|
|
206
206
|
id: `belief-ke-facet-${( this._idSeq++ ).toString( 36 )}`,
|
|
207
207
|
statement: fact,
|
|
@@ -224,7 +224,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
224
224
|
* No-op at boot: mirror params equal the constructor defaults (reconciled in #83).
|
|
225
225
|
*/
|
|
226
226
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
227
|
-
const p = readEffectiveParams( state, 'engine-config-semantic'
|
|
227
|
+
const p = readEffectiveParams( state, 'engine-config-semantic')
|
|
228
228
|
if( p.minIntervalTicks != null ) this._minIntervalTicks = p.minIntervalTicks
|
|
229
229
|
if( p.minNewEpisodes != null ) this._minNewEpisodes = p.minNewEpisodes
|
|
230
230
|
if( p.maxBeliefs != null ) this._maxBeliefs = p.maxBeliefs
|
|
@@ -259,7 +259,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
259
259
|
if( this._episodicConsolidator && this._shouldRunHeuristic( tick ) ){
|
|
260
260
|
const newBeliefs = await this._heuristicPatternDetection( tick, state )
|
|
261
261
|
for( const belief of newBeliefs )
|
|
262
|
-
this._integrateBelief( belief, 'heuristic'
|
|
262
|
+
this._integrateBelief( belief, 'heuristic')
|
|
263
263
|
|
|
264
264
|
this._lastIntegrationTick = tick
|
|
265
265
|
if( this._episodicConsolidator )
|
|
@@ -283,7 +283,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
283
283
|
const prev = belief.confidence
|
|
284
284
|
belief.confidence = Math.max( 0.10, belief.confidence - this._beliefDecayRate )
|
|
285
285
|
if( belief.confidence !== prev )
|
|
286
|
-
SemanticIntegrator._recordHistory( belief, tick, prev, 'decayed'
|
|
286
|
+
SemanticIntegrator._recordHistory( belief, tick, prev, 'decayed')
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
|
|
@@ -315,7 +315,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
315
315
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
316
316
|
const _bus = this._bus
|
|
317
317
|
if( _bus && this._beliefs.length > 0 ){
|
|
318
|
-
const predErr = this._model.observe(
|
|
318
|
+
const predErr = this._model.observe('belief.count', this._beliefs.length )
|
|
319
319
|
if( !predErr.gated )
|
|
320
320
|
_bus.publish({
|
|
321
321
|
type: 'belief.updated',
|
|
@@ -531,7 +531,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
531
531
|
.sort( ( a, b ) => b[1] - a[1] )
|
|
532
532
|
.find( ( [ , count ] ) => count > semanticResults.length * 0.5 )
|
|
533
533
|
|
|
534
|
-
if( dominantSource && dominantSource[0] !== 'unknown'
|
|
534
|
+
if( dominantSource && dominantSource[0] !== 'unknown'){
|
|
535
535
|
beliefs.push({
|
|
536
536
|
id: `belief-semantic-source-${( this._idSeq++ ).toString( 36 )}`,
|
|
537
537
|
statement: `My semantically similar experiences tend to come from: ${dominantSource[0]}`,
|
|
@@ -567,7 +567,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
567
567
|
.map( ( [ tag ] ) => tag )
|
|
568
568
|
|
|
569
569
|
if( topTags.length > 0 ){
|
|
570
|
-
parts.push(
|
|
570
|
+
parts.push(`Themes: ${topTags.join(', ')}`)
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
// Add a sample of recent episode content (first 3, truncated)
|
|
@@ -581,17 +581,17 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
581
581
|
})
|
|
582
582
|
|
|
583
583
|
if( contentSamples.length > 0 ){
|
|
584
|
-
parts.push(
|
|
584
|
+
parts.push(`Recent experiences: ${contentSamples.join('; ')}`)
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
// Add affective context if consistent
|
|
588
588
|
const valenceSum = episodes.reduce( ( s, ep ) => s + ( ep.affectiveContext?.valence ?? 0 ), 0 )
|
|
589
589
|
const meanValence = valenceSum / episodes.length
|
|
590
590
|
if( Math.abs( meanValence ) > 0.2 ){
|
|
591
|
-
parts.push(
|
|
591
|
+
parts.push(`Emotional tone: ${meanValence > 0 ? 'positive' : 'negative'}`)
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
return parts.length > 0 ? parts.join(
|
|
594
|
+
return parts.length > 0 ? parts.join('. ') : 'What patterns emerge from my recent experiences?'
|
|
595
595
|
}
|
|
596
596
|
|
|
597
597
|
// ── Belief management ────────────────────────────────────
|
|
@@ -620,7 +620,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
620
620
|
belief.history = next
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
-
private _integrateBelief( newBelief: Belief, cause = 'created'
|
|
623
|
+
private _integrateBelief( newBelief: Belief, cause = 'created'): Belief {
|
|
624
624
|
const existing = this._beliefs.find( b => this._shouldMerge( b, newBelief ) )
|
|
625
625
|
|
|
626
626
|
if( existing ){
|
|
@@ -628,7 +628,7 @@ export class SemanticIntegrator implements SimulationEngine, CognitiveEngine {
|
|
|
628
628
|
existing.confidence = ( existing.confidence + newBelief.confidence ) / 2
|
|
629
629
|
existing.supportingEpisodes += newBelief.supportingEpisodes
|
|
630
630
|
existing.lastUpdatedAt = newBelief.lastUpdatedAt
|
|
631
|
-
SemanticIntegrator._recordHistory( existing, newBelief.lastUpdatedAt, prev, 'reinforced'
|
|
631
|
+
SemanticIntegrator._recordHistory( existing, newBelief.lastUpdatedAt, prev, 'reinforced')
|
|
632
632
|
return existing
|
|
633
633
|
}
|
|
634
634
|
|
|
@@ -84,10 +84,10 @@ export class SleepPressureRegulator implements SimulationEngine, CognitiveEngine
|
|
|
84
84
|
|
|
85
85
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
86
86
|
this._model.observe( e.type, e.salience )
|
|
87
|
-
if( e.type === 'executive.prediction.formed'
|
|
87
|
+
if( e.type === 'executive.prediction.formed'){
|
|
88
88
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
89
89
|
if( p.predictedDomains.includes('interoception') )
|
|
90
|
-
this._model.setPrecision(
|
|
90
|
+
this._model.setPrecision('sleep.pressure', 1.0 + p.confidence * 0.5 )
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -224,10 +224,10 @@ export class SleepPressureRegulator implements SimulationEngine, CognitiveEngine
|
|
|
224
224
|
// Phase C: publish cognitive event
|
|
225
225
|
const _bus = this._bus
|
|
226
226
|
if( _bus && newPressure > 70 )
|
|
227
|
-
_bus.publish({ type: 'sleep.pressure.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.7, this._model.observe(
|
|
227
|
+
_bus.publish({ type: 'sleep.pressure.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.7, this._model.observe('sleep.critical', newPressure ).salience ), payload: { pressure: newPressure } })
|
|
228
228
|
// Phase D + F: rich state-change event — gated by prediction error
|
|
229
229
|
if( _bus ){
|
|
230
|
-
const predErr = this._model.observe(
|
|
230
|
+
const predErr = this._model.observe('sleep.pressure', newPressure )
|
|
231
231
|
if( !predErr.gated )
|
|
232
232
|
_bus.publish({ type: 'sleep.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { pressure: newPressure, intensity } })
|
|
233
233
|
}
|
|
@@ -88,10 +88,10 @@ export class SocialPerception implements SimulationEngine, CognitiveEngine {
|
|
|
88
88
|
|
|
89
89
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
90
90
|
this._model.observe( e.type, e.salience )
|
|
91
|
-
if( e.type === 'executive.prediction.formed'
|
|
91
|
+
if( e.type === 'executive.prediction.formed'){
|
|
92
92
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
93
93
|
if( p.predictedDomains.includes('social') )
|
|
94
|
-
this._model.setPrecision(
|
|
94
|
+
this._model.setPrecision('social.agent_count', 1.0 + p.confidence * 0.5 )
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -159,7 +159,7 @@ export class SocialPerception implements SimulationEngine, CognitiveEngine {
|
|
|
159
159
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
160
160
|
const _bus = this._bus
|
|
161
161
|
if( _bus && activeAgents > 0 ){
|
|
162
|
-
const predErr = this._model.observe(
|
|
162
|
+
const predErr = this._model.observe('social.agent_count', activeAgents )
|
|
163
163
|
if( !predErr.gated )
|
|
164
164
|
_bus.publish({ type: 'social.agents.present', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { activeAgents } })
|
|
165
165
|
}
|
|
@@ -471,7 +471,7 @@ export class SpacedRepetition implements SimulationEngine, CognitiveEngine {
|
|
|
471
471
|
belief.lastUpdatedAt = tick
|
|
472
472
|
|
|
473
473
|
// Record history if SemanticIntegrator exposes it
|
|
474
|
-
this._recordBeliefHistory( belief, tick, prevConfidence, 'spaced_repetition_reinforced'
|
|
474
|
+
this._recordBeliefHistory( belief, tick, prevConfidence, 'spaced_repetition_reinforced')
|
|
475
475
|
}
|
|
476
476
|
else {
|
|
477
477
|
// Failed review — reset interval and decrease confidence
|
|
@@ -483,7 +483,7 @@ export class SpacedRepetition implements SimulationEngine, CognitiveEngine {
|
|
|
483
483
|
belief.confidence = newConfidence
|
|
484
484
|
belief.lastUpdatedAt = tick
|
|
485
485
|
|
|
486
|
-
this._recordBeliefHistory( belief, tick, prevConfidence, 'spaced_repetition_failed'
|
|
486
|
+
this._recordBeliefHistory( belief, tick, prevConfidence, 'spaced_repetition_failed')
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
record.lastReviewedAt = tick
|
|
@@ -33,6 +33,7 @@ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition
|
|
|
33
33
|
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
34
34
|
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
35
35
|
import { GenerativeModel } from '#cognition/generative.model'
|
|
36
|
+
import { ACP_SELF_PRECISION } from '#cognition/acp'
|
|
36
37
|
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
37
38
|
|
|
38
39
|
export interface StressRegulatorConfig {
|
|
@@ -93,7 +94,9 @@ export class StressRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
93
94
|
// ── Engine interface ─────────────────────────────────────
|
|
94
95
|
|
|
95
96
|
|
|
96
|
-
subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","novelty.state.changed","goal.state.changed","metacognition.state.changed","executive.prediction.formed"
|
|
97
|
+
subscribes(): string[] { return ["energy.state.changed","sleep.state.changed","novelty.state.changed","goal.state.changed","metacognition.state.changed","executive.prediction.formed",
|
|
98
|
+
// ACP-P2: our own enactions — the stress swing they cause is expected
|
|
99
|
+
"agency.enacted","agency.communicate","agency.invocation"] }
|
|
97
100
|
publishes(): CognitiveEventSchema[] { return [] }
|
|
98
101
|
|
|
99
102
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
@@ -120,9 +123,24 @@ export class StressRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
120
123
|
this._model.setPrecision('stress.load', 1.0 + p.confidence * 0.5)
|
|
121
124
|
break
|
|
122
125
|
}
|
|
126
|
+
case 'agency.enacted':
|
|
127
|
+
case 'agency.communicate':
|
|
128
|
+
case 'agency.invocation': {
|
|
129
|
+
// ACP-P2 (final inventoried consumer): we just acted — the stress
|
|
130
|
+
// swing that follows is our own doing. Precision-only (no directional
|
|
131
|
+
// prior: acting can LOAD or RELIEVE, so we don't pretend to know the
|
|
132
|
+
// sign); react() restores after one observe so a genuine world
|
|
133
|
+
// stressor next tick lands at full weight.
|
|
134
|
+
this._model.setPrecision('stress.load', ACP_SELF_PRECISION )
|
|
135
|
+
this._acpOneShot = true
|
|
136
|
+
break
|
|
137
|
+
}
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
/** ACP-P2: self-caused stress attenuation armed; react() restores after one observe. */
|
|
142
|
+
private _acpOneShot = false
|
|
143
|
+
|
|
126
144
|
snapshot(): Record<string, unknown> {
|
|
127
145
|
return {
|
|
128
146
|
energyLevel: this._energyLevel,
|
|
@@ -261,12 +279,17 @@ export class StressRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
261
279
|
|
|
262
280
|
// Phase C: publish cognitive event
|
|
263
281
|
const _bus = this._bus
|
|
264
|
-
if( _bus && ( zone === 'distress' || zone === 'overload'
|
|
282
|
+
if( _bus && ( zone === 'distress' || zone === 'overload') )
|
|
265
283
|
_bus.publish({ type: 'stress.zone.transition', version: 1, sourceEngine: this.name, salience: Math.min(1, newLoad / 100), payload: { zone, load: newLoad } })
|
|
266
284
|
// Phase D + F: rich state-change event — gated by prediction error
|
|
267
285
|
if( _bus ){
|
|
268
286
|
const zoneCode = zone === 'low' ? 0 : zone === 'optimal' ? 1 : zone === 'distress' ? 2 : 3
|
|
269
|
-
const predErr = this._model.observe(
|
|
287
|
+
const predErr = this._model.observe('stress.load', newLoad )
|
|
288
|
+
// ACP-P2: self-caused observe done — restore full precision immediately.
|
|
289
|
+
if( this._acpOneShot ){
|
|
290
|
+
this._model.setPrecision('stress.load', 1.0 )
|
|
291
|
+
this._acpOneShot = false
|
|
292
|
+
}
|
|
270
293
|
if( !predErr.gated || zone !== previousZone ){
|
|
271
294
|
_bus.publish({ type: 'stress.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { load: newLoad, zoneCode, deadlineUrgency: state.metrics.get('deadline.urgency') ?? 0, cognitiveLoad: state.metrics.get('cognitive.load') ?? state.metrics.get('attention.usage') ?? 0 } })
|
|
272
295
|
}
|
|
@@ -279,7 +302,7 @@ export class StressRegulator implements SimulationEngine, CognitiveEngine {
|
|
|
279
302
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
280
303
|
// Effective config = base engine-config-stress ⊕ persona-prior. Channel A: a steadier
|
|
281
304
|
// (emotionally-stable) Will develops a higher baseDecayRate and so sheds stress faster.
|
|
282
|
-
const p = readEffectiveParams( state, 'engine-config-stress'
|
|
305
|
+
const p = readEffectiveParams( state, 'engine-config-stress')
|
|
283
306
|
if( p.baseDecayRate != null ) this._baseDecayRate = p.baseDecayRate
|
|
284
307
|
if( p.optimalThreshold != null ) this._optimalThreshold = p.optimalThreshold
|
|
285
308
|
if( p.distressThreshold != null ) this._distressThreshold = p.distressThreshold
|
|
@@ -81,7 +81,7 @@ export class TaskSwitcher implements SimulationEngine, CognitiveEngine {
|
|
|
81
81
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
82
82
|
// Effective config = base engine-config-task-switcher ⊕ persona-prior. Channel A: a
|
|
83
83
|
// conscientious Will develops a higher baseSwitchCost and so is less distractible.
|
|
84
|
-
const p = readEffectiveParams( state, 'engine-config-task-switcher'
|
|
84
|
+
const p = readEffectiveParams( state, 'engine-config-task-switcher')
|
|
85
85
|
if( p.baseSwitchCost != null ) this._baseSwitchCost = p.baseSwitchCost
|
|
86
86
|
if( p.switchThreshold != null ) this._switchThreshold = p.switchThreshold
|
|
87
87
|
if( p.minFocusTicks != null ) this._minFocusTicks = p.minFocusTicks
|
|
@@ -93,10 +93,10 @@ export class TaskSwitcher implements SimulationEngine, CognitiveEngine {
|
|
|
93
93
|
|
|
94
94
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
95
95
|
this._model.observe( e.type, e.salience )
|
|
96
|
-
if( e.type === 'executive.prediction.formed'
|
|
96
|
+
if( e.type === 'executive.prediction.formed'){
|
|
97
97
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
98
98
|
if( p.predictedDomains.includes('executive') )
|
|
99
|
-
this._model.setPrecision(
|
|
99
|
+
this._model.setPrecision('task.focus_ticks', 1.0 + p.confidence * 0.5 )
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -143,8 +143,13 @@ export class TaskSwitcher implements SimulationEngine, CognitiveEngine {
|
|
|
143
143
|
const currentPriority = currentGoal?.priority ?? 0
|
|
144
144
|
const switchAdvantage = topGoal.priority - currentPriority
|
|
145
145
|
|
|
146
|
-
// Account for switching cost
|
|
147
|
-
|
|
146
|
+
// Account for switching cost. EXAFFERENCE P3 follow-up: `situation.stability`
|
|
147
|
+
// (absent ⇒ 1 ⇒ unchanged) scales the focus-hardening term, so a
|
|
148
|
+
// destabilized world loosens focus here exactly as it does in the
|
|
149
|
+
// ActionSelector — the two owners of switch resistance now read the same
|
|
150
|
+
// stability signal at their native scales (goal-priority vs. activation).
|
|
151
|
+
const stability = state.metrics.get('situation.stability') ?? 1
|
|
152
|
+
const switchCost = this._baseSwitchCost * ( 1 + this._currentFocus.focusTicks * 0.01 * stability )
|
|
148
153
|
const netBenefit = switchAdvantage - switchCost
|
|
149
154
|
|
|
150
155
|
if( netBenefit > this._switchThreshold
|
|
@@ -204,7 +209,7 @@ export class TaskSwitcher implements SimulationEngine, CognitiveEngine {
|
|
|
204
209
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
205
210
|
const _bus = this._bus
|
|
206
211
|
if( _bus ){
|
|
207
|
-
const predErr = this._model.observe(
|
|
212
|
+
const predErr = this._model.observe('task.focus_ticks', this._currentFocus.focusTicks )
|
|
208
213
|
if( !predErr.gated )
|
|
209
214
|
_bus.publish({ type: 'task.focus.changed', version: 1, sourceEngine: this.name, salience: Math.max( 0.3, predErr.salience ), payload: { focusTicks: this._currentFocus.focusTicks } })
|
|
210
215
|
}
|
|
@@ -98,17 +98,17 @@ export class TheoryOfMind implements SimulationEngine, CognitiveEngine {
|
|
|
98
98
|
|
|
99
99
|
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
100
100
|
this._model.observe( e.type, e.salience )
|
|
101
|
-
if( e.type === 'executive.prediction.formed'
|
|
101
|
+
if( e.type === 'executive.prediction.formed'){
|
|
102
102
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
103
103
|
if( p.predictedDomains.includes('social') )
|
|
104
|
-
this._model.setPrecision(
|
|
104
|
+
this._model.setPrecision('tom.models', 1.0 + p.confidence * 0.5 )
|
|
105
105
|
}
|
|
106
|
-
if( e.type === 'interaction.occurred'
|
|
106
|
+
if( e.type === 'interaction.occurred'){
|
|
107
107
|
const p = e.payload as {
|
|
108
108
|
keid: string; valence: number; intensity: number
|
|
109
109
|
directedAtSelf: boolean; interactionType: string
|
|
110
110
|
}
|
|
111
|
-
if( p.keid && p.keid !== 'agent-self'
|
|
111
|
+
if( p.keid && p.keid !== 'agent-self')
|
|
112
112
|
this._pendingInteractions.push( p )
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -191,7 +191,7 @@ export class TheoryOfMind implements SimulationEngine, CognitiveEngine {
|
|
|
191
191
|
// Phase C + F: publish cognitive event — gated by prediction error
|
|
192
192
|
const _bus = this._bus
|
|
193
193
|
if( _bus && this._models.size > 0 ){
|
|
194
|
-
const predErr = this._model.observe(
|
|
194
|
+
const predErr = this._model.observe('tom.models', this._models.size )
|
|
195
195
|
if( !predErr.gated )
|
|
196
196
|
_bus.publish({ type: 'theory_of_mind.model.updated', version: 1, sourceEngine: this.name, salience: Math.max( 0.2, predErr.salience ), payload: { modelsActive: this._models.size } })
|
|
197
197
|
}
|
|
@@ -231,7 +231,7 @@ export class TheoryOfMind implements SimulationEngine, CognitiveEngine {
|
|
|
231
231
|
*/
|
|
232
232
|
private _restoreFromState( state: ReadonlySimulationState ): void {
|
|
233
233
|
for( const entity of state.entities.values() ){
|
|
234
|
-
if( entity.type !== 'theory_of_mind'
|
|
234
|
+
if( entity.type !== 'theory_of_mind') continue
|
|
235
235
|
const m = entity.metadata ?? {}
|
|
236
236
|
const keid = m['keid'] as string | undefined
|
|
237
237
|
if( !keid ) continue
|
|
@@ -180,12 +180,12 @@ export class ThreatEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
180
180
|
// event is refreshed each tick as base ⊕ persona-prior, so a steadier Will develops a
|
|
181
181
|
// HIGHER threshold and is less easily alarmed. _computeAndEmit (no `state`) reads the
|
|
182
182
|
// cached field. (The seed entity existed but was ignored before.)
|
|
183
|
-
this._fearEventThreshold = readEffectiveParams( state, 'engine-config-threat'
|
|
183
|
+
this._fearEventThreshold = readEffectiveParams( state, 'engine-config-threat').fearEventThreshold ?? this._fearEventThreshold
|
|
184
184
|
|
|
185
185
|
// Recompute hostile threat from state entities every tick
|
|
186
186
|
let maxHostile = 0
|
|
187
187
|
for( const entity of state.entities.values() ){
|
|
188
|
-
if( entity.type !== 'threat'
|
|
188
|
+
if( entity.type !== 'threat') continue
|
|
189
189
|
if( entity.metadata?.active === false ) continue
|
|
190
190
|
if( !entity.metadata?.hostile ) continue
|
|
191
191
|
const intensity = typeof entity.metadata?.intensity === 'number'
|
|
@@ -288,7 +288,7 @@ export class ThreatEvaluator implements SimulationEngine, CognitiveEngine {
|
|
|
288
288
|
// worldState.threatLevel). observe() runs every tick so the baseline tracks
|
|
289
289
|
// and the executive's top-down precision (set on 'threat.level') applies;
|
|
290
290
|
// the one value is reused across the tiered events.
|
|
291
|
-
const threatSalience = this._model.observe(
|
|
291
|
+
const threatSalience = this._model.observe('threat.level', threatLevel ).salience
|
|
292
292
|
|
|
293
293
|
if( fear > 0.4 )
|
|
294
294
|
_bus.publish({ type: 'emotion.fear.elevated', version: 1, sourceEngine: this.name, salience: threatSalience, payload: { fear } })
|
|
@@ -132,7 +132,7 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
132
132
|
case 'executive.prediction.formed': {
|
|
133
133
|
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
134
134
|
if( p.predictedDomains.includes('memory') )
|
|
135
|
-
this._model.setPrecision(
|
|
135
|
+
this._model.setPrecision('memory.working.load', 1.0 + p.confidence * 0.5 )
|
|
136
136
|
break
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -174,7 +174,7 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
174
174
|
* No-op at boot: mirror params equal the constructor defaults (reconciled in #83).
|
|
175
175
|
*/
|
|
176
176
|
private _readConfigFromState( state: ReadonlySimulationState ): void {
|
|
177
|
-
const p = readEffectiveParams( state, 'engine-config-working-memory'
|
|
177
|
+
const p = readEffectiveParams( state, 'engine-config-working-memory')
|
|
178
178
|
if( p.maxChunks != null ) this._maxChunks = p.maxChunks
|
|
179
179
|
if( p.baseDecayRate != null ) this._baseDecayRate = p.baseDecayRate
|
|
180
180
|
if( p.attentionProtection != null ) this._attentionProtection = p.attentionProtection
|
|
@@ -241,7 +241,7 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
241
241
|
type: 'memory.working.changed',
|
|
242
242
|
version: 1,
|
|
243
243
|
sourceEngine: this.name,
|
|
244
|
-
salience: this._model.observe(
|
|
244
|
+
salience: this._model.observe('memory.working.load', load ).salience,
|
|
245
245
|
payload: { items: this._items.length, capacity: this._modulatedCapacity, load },
|
|
246
246
|
})
|
|
247
247
|
|
|
@@ -275,10 +275,10 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
275
275
|
*/
|
|
276
276
|
private _ingestPercepts( state: ReadonlySimulationState, tick: Tick ): void {
|
|
277
277
|
for( const entity of state.entities.values() ){
|
|
278
|
-
if( entity.type !== 'percept'
|
|
278
|
+
if( entity.type !== 'percept') continue
|
|
279
279
|
if( this._items.some( i => i.sourceEntityId === entity.id ) ) continue
|
|
280
280
|
|
|
281
|
-
const summary = ( entity.metadata?.summary ?? entity.metadata?.content ?? ''
|
|
281
|
+
const summary = ( entity.metadata?.summary ?? entity.metadata?.content ?? '') as string
|
|
282
282
|
if( !summary || summary.startsWith('New percept:') ) continue
|
|
283
283
|
|
|
284
284
|
this._evictIfNeeded()
|
|
@@ -301,8 +301,8 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
301
301
|
*/
|
|
302
302
|
private _ingestGoals( state: ReadonlySimulationState, tick: Tick ): void {
|
|
303
303
|
for( const entity of state.entities.values() ){
|
|
304
|
-
if( entity.type !== 'goal'
|
|
305
|
-
if( entity.metadata?.status !== 'active'
|
|
304
|
+
if( entity.type !== 'goal') continue
|
|
305
|
+
if( entity.metadata?.status !== 'active') continue
|
|
306
306
|
if( this._items.some( i => i.sourceEntityId === entity.id ) ) continue
|
|
307
307
|
|
|
308
308
|
this._evictIfNeeded()
|
|
@@ -335,7 +335,7 @@ export class WorkingMemory implements SimulationEngine, CognitiveEngine {
|
|
|
335
335
|
|
|
336
336
|
// State-entity fallback: attention.focus entities
|
|
337
337
|
for( const entity of state.entities.values() ){
|
|
338
|
-
if( entity.type !== 'attention.focus'
|
|
338
|
+
if( entity.type !== 'attention.focus') continue
|
|
339
339
|
const targetId = entity.metadata?.targetEntityId as string | undefined
|
|
340
340
|
if( !targetId ) continue
|
|
341
341
|
const item = this._items.find( i => i.sourceEntityId === targetId )
|
|
@@ -289,8 +289,8 @@ export class GenerativeModel {
|
|
|
289
289
|
*/
|
|
290
290
|
restore( snap: GenerativeModelSnapshot | undefined | null ): void {
|
|
291
291
|
if( !snap ) return
|
|
292
|
-
if( typeof snap.defaultAlpha === 'number'
|
|
293
|
-
if( typeof snap.defaultRange === 'number'
|
|
292
|
+
if( typeof snap.defaultAlpha === 'number') this._defaultAlpha = snap.defaultAlpha
|
|
293
|
+
if( typeof snap.defaultRange === 'number') this._defaultRange = snap.defaultRange
|
|
294
294
|
|
|
295
295
|
this._streams = new Map(
|
|
296
296
|
( snap.streams ?? [] ).map( ([ k, v ]) => [ k, {
|
|
@@ -104,7 +104,7 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
104
104
|
if( this._index.size >= this._maxIndexedEpisodes )
|
|
105
105
|
await this._evictColdest()
|
|
106
106
|
|
|
107
|
-
const embedding = await this._embedder.embed( episodeContentToText( content ), 'index'
|
|
107
|
+
const embedding = await this._embedder.embed( episodeContentToText( content ), 'index')
|
|
108
108
|
|
|
109
109
|
const record: VectorRecord = {
|
|
110
110
|
id: episode.id,
|
|
@@ -138,7 +138,7 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
138
138
|
await this._evictColdest()
|
|
139
139
|
|
|
140
140
|
const contents = newEpisodes.map( e => episodeContentToText( e.content ) )
|
|
141
|
-
const embeddings = await this._embedder.embedBatch( contents, 'index'
|
|
141
|
+
const embeddings = await this._embedder.embedBatch( contents, 'index')
|
|
142
142
|
|
|
143
143
|
for( let i = 0; i < newEpisodes.length; i++ ){
|
|
144
144
|
const { episode } = newEpisodes[i]!
|
|
@@ -167,7 +167,7 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
async search( query: unknown, filter?: VectorQueryFilter ): Promise<VectorQueryResult[]> {
|
|
170
|
-
const embedding = await this._embedder.embed( episodeContentToText( query ), 'recall'
|
|
170
|
+
const embedding = await this._embedder.embed( episodeContentToText( query ), 'recall')
|
|
171
171
|
return this.searchWithVector( embedding, filter )
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -275,7 +275,7 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
catch( err ){
|
|
278
|
-
logger.warn(
|
|
278
|
+
logger.warn(`[VectorMemoryAdapter] Failed to load index:`, err )
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
@@ -308,7 +308,7 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
308
308
|
|
|
309
309
|
this._persistDebounceTimer = setTimeout( () => {
|
|
310
310
|
this.persist().catch( err => {
|
|
311
|
-
logger.error(
|
|
311
|
+
logger.error(`[VectorMemoryAdapter] Persist failed:`, err )
|
|
312
312
|
} )
|
|
313
313
|
this._persistDebounceTimer = null
|
|
314
314
|
}, 5000 )
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
* strings are already clean text and pass through unchanged.
|
|
19
19
|
*/
|
|
20
20
|
export function episodeContentToText( content: unknown ): string {
|
|
21
|
-
if( typeof content === 'string'
|
|
21
|
+
if( typeof content === 'string') return content
|
|
22
22
|
|
|
23
|
-
if( content && typeof content === 'object'
|
|
23
|
+
if( content && typeof content === 'object'){
|
|
24
24
|
const m = content as Record<string, unknown>
|
|
25
25
|
|
|
26
26
|
// Conversation exchanges carry the actual dialogue — by far the strongest
|
|
@@ -28,7 +28,7 @@ export function episodeContentToText( content: unknown ): string {
|
|
|
28
28
|
const user = typeof m['userMessage'] === 'string' ? m['userMessage'] as string : ''
|
|
29
29
|
const reply = typeof m['willReply'] === 'string' ? m['willReply'] as string : ''
|
|
30
30
|
if( user || reply )
|
|
31
|
-
return [ user, reply ].filter( Boolean ).join(
|
|
31
|
+
return [ user, reply ].filter( Boolean ).join(' → ')
|
|
32
32
|
|
|
33
33
|
// Most WM items carry a top-level human summary.
|
|
34
34
|
if( typeof m['summary'] === 'string' && m['summary'] ) return m['summary'] as string
|
|
@@ -36,7 +36,7 @@ export function episodeContentToText( content: unknown ): string {
|
|
|
36
36
|
// Descriptor items nest their payload (e.g. plan: { content: { summary } }).
|
|
37
37
|
const nested = m['content']
|
|
38
38
|
if( typeof nested === 'string' && nested ) return nested
|
|
39
|
-
if( nested && typeof nested === 'object'
|
|
39
|
+
if( nested && typeof nested === 'object'){
|
|
40
40
|
const nm = nested as Record<string, unknown>
|
|
41
41
|
if( typeof nm['summary'] === 'string' && nm['summary'] ) return nm['summary'] as string
|
|
42
42
|
}
|