@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
|
@@ -103,6 +103,9 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
103
103
|
// means the executor, which ticks later in the SAME tick, sees a whole
|
|
104
104
|
// repertoire and can expand a restored mid-flight macro. Idempotent.
|
|
105
105
|
this._repertoire?.restoreComposites( state.entities )
|
|
106
|
+
// Availability entries (P2) rehydrate the same way, so a restored Will keeps
|
|
107
|
+
// its learned suppressions instead of re-probing forbidden abilities.
|
|
108
|
+
this._repertoire?.restoreAvailability( state.entities )
|
|
106
109
|
|
|
107
110
|
const schemas = this._repertoire?.schemas() ?? this._schemas
|
|
108
111
|
const skills = this._skills?.() ?? this._repertoire?.skills() ?? null
|
|
@@ -114,14 +117,12 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
114
117
|
|
|
115
118
|
// Clear the previous tick's field — affordances are transient.
|
|
116
119
|
for( const [ id, e ] of state.entities )
|
|
117
|
-
if( e.type === 'affordance'
|
|
120
|
+
if( e.type === 'affordance') del.push( id )
|
|
118
121
|
|
|
119
122
|
// ── 1. innate floor — always emitted, never attention-capped ──
|
|
120
|
-
const floor = schemas.filter( s => s.binds === 'none'
|
|
123
|
+
const floor = schemas.filter( s => s.binds === 'none')
|
|
121
124
|
for( const schema of floor )
|
|
122
|
-
set.push( this._toEntity(
|
|
123
|
-
this._build( schema, tick, state, valence, energyLow, skills, {} ),
|
|
124
|
-
) )
|
|
125
|
+
set.push( this._toEntity( this._build( schema, tick, state, valence, energyLow, skills, {} ) ) )
|
|
125
126
|
|
|
126
127
|
// ── 2. perception-bound candidates, attention-budgeted ───────
|
|
127
128
|
// Goal-relevance counts at the CAP, not only at selection: an affordance whose
|
|
@@ -131,14 +132,16 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
131
132
|
const candidates: Candidate[] = []
|
|
132
133
|
const goalTargets: Map<string, number> = collectGoalTargets( state )
|
|
133
134
|
|
|
134
|
-
const perceptSchema = schemas.find( s => s.binds === 'percept'
|
|
135
|
+
const perceptSchema = schemas.find( s => s.binds === 'percept')
|
|
135
136
|
if( perceptSchema )
|
|
136
137
|
for( const [ id, e ] of state.entities ){
|
|
137
|
-
if( e.type !== 'percept'
|
|
138
|
+
if( e.type !== 'percept') continue
|
|
139
|
+
|
|
138
140
|
const m = e.metadata
|
|
139
141
|
const salience = num( m?.['salience'], 0 )
|
|
140
142
|
const summary = str( m?.['summary'] ) ?? str( m?.['category'] ) ?? 'something'
|
|
141
143
|
const target = str( m?.['entityId'] ) ?? str( m?.['targetEntityId'] )
|
|
144
|
+
|
|
142
145
|
candidates.push({
|
|
143
146
|
salience: salience + ( target ? goalTargets.get( target ) ?? 0 : 0 ),
|
|
144
147
|
affordance: this._build( perceptSchema, tick, state, valence, energyLow, skills, {
|
|
@@ -155,21 +158,26 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
155
158
|
// things — so the Will can direct `give`/`greet` at someone or `use`/`pick-up`
|
|
156
159
|
// at something in particular. Each (schema × target) enters as a candidate at
|
|
157
160
|
// the target's salience and competes through the attention cap.
|
|
158
|
-
const personSchemas = schemas.filter( s => s.binds === 'entity'
|
|
159
|
-
const objectSchemas = schemas.filter( s => s.binds === 'object'
|
|
161
|
+
const personSchemas = schemas.filter( s => s.binds === 'entity')
|
|
162
|
+
const objectSchemas = schemas.filter( s => s.binds === 'object')
|
|
163
|
+
|
|
160
164
|
if( personSchemas.length > 0 || objectSchemas.length > 0 )
|
|
161
165
|
for( const [ id, e ] of state.entities ){
|
|
162
|
-
if( e.type !== 'known-entity'
|
|
166
|
+
if( e.type !== 'known-entity') continue
|
|
167
|
+
|
|
163
168
|
const m = e.metadata
|
|
164
169
|
const kind = str( m?.['kind'] )
|
|
165
170
|
const applicable = kind === 'sentient' ? personSchemas : kind === 'thing' ? objectSchemas : null
|
|
171
|
+
|
|
166
172
|
if( !applicable || applicable.length === 0 ) continue
|
|
173
|
+
|
|
167
174
|
const keid = str( m?.['keid'] ) ?? id
|
|
168
175
|
const fam = num( m?.['familiarity'], 0 )
|
|
169
176
|
const val = num( m?.['valence'], 0 )
|
|
170
177
|
const res = num( m?.['resolutionConfidence'], 0 )
|
|
171
178
|
const salience = fam * 0.6 + Math.max( 0, val ) * 0.3 + res * 0.1 + ( goalTargets.get( keid ) ?? 0 )
|
|
172
179
|
const name = str( m?.['name'] ) ?? keid
|
|
180
|
+
|
|
173
181
|
for( const schema of applicable )
|
|
174
182
|
candidates.push({
|
|
175
183
|
salience,
|
|
@@ -188,11 +196,14 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
188
196
|
// it. This is the AffordanceSource.ideomotor leg: executive intention → an
|
|
189
197
|
// affordance that competes like any other.
|
|
190
198
|
for( const [ id, e ] of state.entities ){
|
|
191
|
-
if( e.type !== 'ideomotor.intent'
|
|
199
|
+
if( e.type !== 'ideomotor.intent') continue
|
|
200
|
+
|
|
192
201
|
const m = e.metadata
|
|
193
202
|
const schemaId = str( m?.['schema'] )
|
|
194
203
|
const schema = schemaId ? schemas.find( s => s.id === schemaId ) : undefined
|
|
204
|
+
|
|
195
205
|
if( !schema ) continue
|
|
206
|
+
|
|
196
207
|
candidates.push({
|
|
197
208
|
salience: IDEOMOTOR_BASE_SALIENCE + num( m?.['priority'], 0.8 ),
|
|
198
209
|
affordance: this._build( schema, tick, state, valence, energyLow, skills, {
|
|
@@ -215,11 +226,14 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
215
226
|
// next tick. The suggested schema must resolve in the repertoire; if it does not,
|
|
216
227
|
// the prior cannot surface as an action and the plan waits / replans.
|
|
217
228
|
for( const [ id, e ] of state.entities ){
|
|
218
|
-
if( e.type !== 'plan.prior'
|
|
229
|
+
if( e.type !== 'plan.prior') continue
|
|
230
|
+
|
|
219
231
|
const m = e.metadata
|
|
220
232
|
const schemaId = str( m?.['schema'] )
|
|
221
233
|
const schema = schemaId ? schemas.find( s => s.id === schemaId ) : undefined
|
|
234
|
+
|
|
222
235
|
if( !schema ) continue
|
|
236
|
+
|
|
223
237
|
const planBias = clamp01( num( m?.['planBias'], 0.6 ) )
|
|
224
238
|
candidates.push({
|
|
225
239
|
salience: IDEOMOTOR_BASE_SALIENCE + planBias,
|
|
@@ -266,7 +280,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
266
280
|
})
|
|
267
281
|
}
|
|
268
282
|
catch( err ){
|
|
269
|
-
logger.warn(
|
|
283
|
+
logger.warn(`[affordance] bus publish failed: ${ err instanceof Error ? err.message : String( err ) }`)
|
|
270
284
|
}
|
|
271
285
|
}
|
|
272
286
|
|
|
@@ -295,9 +309,12 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
295
309
|
): Affordance {
|
|
296
310
|
const skill = skills?.get( schema.id )
|
|
297
311
|
|
|
312
|
+
// Policy availability (P2): omitted when fully available (1), so a never-refused
|
|
313
|
+
// Will's affordance field is byte-identical. Present only once a refusal dented it.
|
|
314
|
+
const availability = this._repertoire?.availabilityOf( schema.id ) ?? 1
|
|
315
|
+
|
|
298
316
|
// Learned value if known, else the schema's intrinsic prior mapped to 0..1.
|
|
299
|
-
const expectedReward = skill?.valueEstimate
|
|
300
|
-
?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
|
|
317
|
+
const expectedReward = skill?.valueEstimate ?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
|
|
301
318
|
const expectedValence = schema.baseValence ?? valence
|
|
302
319
|
const habitStrength = skill?.habitStrength ?? 0
|
|
303
320
|
// Low energy makes everything feel costlier.
|
|
@@ -323,6 +340,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
323
340
|
available: this._available( schema.preconditions, ( k ) => metric( state, k, 0 ) ),
|
|
324
341
|
tags: schema.tags ?? [],
|
|
325
342
|
...( schema.description ? { description: schema.description } : {} ),
|
|
343
|
+
...( availability < 1 ? { availability } : {} ),
|
|
326
344
|
planBias: ctx.planBias,
|
|
327
345
|
planId: ctx.planId,
|
|
328
346
|
stepId: ctx.stepId,
|
|
@@ -347,6 +365,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
347
365
|
available: a.available,
|
|
348
366
|
tags: a.tags,
|
|
349
367
|
description: a.description,
|
|
368
|
+
...( a.availability !== undefined ? { availability: a.availability } : {} ),
|
|
350
369
|
planBias: a.planBias,
|
|
351
370
|
planId: a.planId,
|
|
352
371
|
stepId: a.stepId,
|
|
@@ -374,7 +393,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
374
393
|
}
|
|
375
394
|
|
|
376
395
|
private _attentionCap( state: ReadonlySimulationState ): number {
|
|
377
|
-
const cap = state.metrics.get(
|
|
396
|
+
const cap = state.metrics.get('attention.capacity') ?? this._defaultCap
|
|
378
397
|
return Math.max( 1, Math.min( MAX_ATTENTION_CAP, Math.round( cap ) ) )
|
|
379
398
|
}
|
|
380
399
|
}
|
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
import type { CognitiveBus } from '#cognition/bus'
|
|
31
31
|
import type { CognitiveEngine, EngineResult } from '#cognition/types'
|
|
32
32
|
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
33
|
+
import { revokedIntentIds, revocationId } from '#agency/revocation'
|
|
33
34
|
|
|
34
35
|
// ── Minimal structural view of the executive's facet machinery ───────────────
|
|
35
36
|
// Kept structural (not an import of the executive engine) so the agency module
|
|
@@ -42,7 +43,7 @@ interface DeliberationFacetHandle {
|
|
|
42
43
|
destroy(): void
|
|
43
44
|
}
|
|
44
45
|
export interface DeliberationFacetProvider {
|
|
45
|
-
spawnFacet( role?: 'deliberation'
|
|
46
|
+
spawnFacet( role?: 'deliberation'): { attention: 'available' | 'full'; handle?: DeliberationFacetHandle }
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
interface Candidate {
|
|
@@ -92,15 +93,23 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
92
93
|
state: ReadonlySimulationState,
|
|
93
94
|
_context: SimulationContext,
|
|
94
95
|
): Promise<EngineResult> {
|
|
96
|
+
// Honor commitment revocations first (EXAFFERENCE P4): a `deliberating`
|
|
97
|
+
// intent under a live tombstone is dropped — the world ruptured hard enough
|
|
98
|
+
// to let go of it — and the tombstone with it. We never deliberate a
|
|
99
|
+
// revoked intent.
|
|
100
|
+
const revoked = revokedIntentIds( state.entities, tick )
|
|
101
|
+
const del: string[] = []
|
|
102
|
+
|
|
95
103
|
// One deliberation per tick (the serial bottleneck).
|
|
96
104
|
let target: { id: string; meta: Record<string, unknown> } | null = null
|
|
97
105
|
for( const [ id, e ] of state.entities ){
|
|
98
|
-
if( e.type !== 'agency.intent'
|
|
99
|
-
if( str( e.metadata?.['status'] ) !== 'deliberating'
|
|
106
|
+
if( e.type !== 'agency.intent') continue
|
|
107
|
+
if( str( e.metadata?.['status'] ) !== 'deliberating') continue
|
|
108
|
+
if( revoked.has( id ) ){ del.push( id, revocationId( id ) ); continue } // revoked → drop
|
|
100
109
|
const meta = ( e.metadata ?? {} ) as Record<string, unknown>
|
|
101
110
|
if( !target || id < target.id ) target = { id, meta } // stable pick
|
|
102
111
|
}
|
|
103
|
-
if( !target ) return { commands: {} }
|
|
112
|
+
if( !target ) return del.length > 0 ? { commands: { delete: del } } : { commands: {} }
|
|
104
113
|
|
|
105
114
|
const { id, meta } = target
|
|
106
115
|
const provisional = str( meta['schema'] ) ?? 'wait'
|
|
@@ -108,7 +117,8 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
108
117
|
|
|
109
118
|
// No executive → confirm the substrate's winner (graceful System-1).
|
|
110
119
|
if( !this._provider )
|
|
111
|
-
return { commands: { set: [ this._commit( id, meta, provisional, candidates, 'no-executive'
|
|
120
|
+
return { commands: { set: [ this._commit( id, meta, provisional, candidates, 'no-executive') ],
|
|
121
|
+
...( del.length > 0 ? { delete: del } : {} ) } }
|
|
112
122
|
|
|
113
123
|
// Deliberate through a UNIFIED facet (same persona/context as the master).
|
|
114
124
|
const chosen = await this._deliberate( state, candidates, provisional, meta )
|
|
@@ -126,7 +136,8 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
126
136
|
|
|
127
137
|
return {
|
|
128
138
|
commands: {
|
|
129
|
-
set: [ this._commit( id, meta, chosen, candidates, 'facet'
|
|
139
|
+
set: [ this._commit( id, meta, chosen, candidates, 'facet') ],
|
|
140
|
+
...( del.length > 0 ? { delete: del } : {} ),
|
|
130
141
|
metrics: [ [ 'agency.deliberation.count', 1 ] ],
|
|
131
142
|
},
|
|
132
143
|
}
|
|
@@ -145,7 +156,7 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
145
156
|
if( !this._handle ){
|
|
146
157
|
const spawned = this._provider!.spawnFacet('deliberation')
|
|
147
158
|
if( spawned.attention === 'full' || !spawned.handle ){
|
|
148
|
-
logger.info(
|
|
159
|
+
logger.info('[deliberation] facet budget full — confirming substrate winner')
|
|
149
160
|
return provisional
|
|
150
161
|
}
|
|
151
162
|
this._handle = spawned.handle
|
|
@@ -170,7 +181,7 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
170
181
|
// Director/state not ready (e.g. executive hasn't run yet) or LLM failure →
|
|
171
182
|
// fall back to the substrate winner. Drop a possibly-dead handle.
|
|
172
183
|
this._handle = null
|
|
173
|
-
logger.warn(
|
|
184
|
+
logger.warn(`[deliberation] facet unavailable, confirming winner: ${ err instanceof Error ? err.message : String( err ) }`)
|
|
174
185
|
return provisional
|
|
175
186
|
}
|
|
176
187
|
}
|
|
@@ -208,10 +219,13 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
208
219
|
// Channel B: if this choice arose by interrupting a pending action, name it so the
|
|
209
220
|
// facet owns the interruption in-character rather than reasoning in a vacuum.
|
|
210
221
|
const preemptedFrom = str( meta['preemptedFrom'] )
|
|
211
|
-
|
|
212
|
-
|
|
222
|
+
const revokedBy = str( meta['revokedBy'] )
|
|
223
|
+
if( revokedBy )
|
|
224
|
+
lines.push(`Something in my situation just shifted and I let go of what I was weighing ("${ revokedBy }"). Decide afresh what to do now:`)
|
|
225
|
+
else if( preemptedFrom )
|
|
226
|
+
lines.push(`I just broke off a pending action ("${ preemptedFrom }") because something more pressing pulled at me. Decide what to do now:`)
|
|
213
227
|
else
|
|
214
|
-
lines.push(
|
|
228
|
+
lines.push('My automatic action-selection was uncertain. Candidate actions:')
|
|
215
229
|
candidates.forEach( ( c, i ) => {
|
|
216
230
|
const to = c.targetEntityId ? ` toward ${ c.targetEntityId }` : ''
|
|
217
231
|
// The ability's meaning, so the facet weighs what each option IS FOR rather
|
|
@@ -220,9 +234,9 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
220
234
|
// Channel B: name the plan link so the facet chooses as the self pursuing it,
|
|
221
235
|
// not blindly among labels ("this one is the next step of the plan I'm on").
|
|
222
236
|
const plan = c.fromPlan ? " (my current plan's next step)" : ''
|
|
223
|
-
lines.push(
|
|
237
|
+
lines.push(`${ i + 1 }. ${ c.schema }${ to }${ what }${ plan }`)
|
|
224
238
|
})
|
|
225
|
-
return lines.join(
|
|
239
|
+
return lines.join('\n')
|
|
226
240
|
}
|
|
227
241
|
}
|
|
228
242
|
|
|
@@ -230,7 +244,7 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
230
244
|
|
|
231
245
|
/** Pull the chosen schema from a facet decision, validated against the candidates. */
|
|
232
246
|
function extractChosen( decision: unknown, candidates: Candidate[] ): string | undefined {
|
|
233
|
-
if( !decision || typeof decision !== 'object'
|
|
247
|
+
if( !decision || typeof decision !== 'object') return undefined
|
|
234
248
|
const actions = ( decision as Record<string, unknown> )['actions']
|
|
235
249
|
if( !Array.isArray( actions ) ) return undefined
|
|
236
250
|
const valid = new Set( candidates.map( c => c.schema ) )
|
|
@@ -38,9 +38,16 @@ import type { AccessGrants } from '#agency/access.grants'
|
|
|
38
38
|
import type { ActionRequest, ActionResult } from '#types'
|
|
39
39
|
import { INNATE_SCHEMAS } from '#agency/schemas/innate'
|
|
40
40
|
import { enact, type Enaction } from '#agency/execution.primitives'
|
|
41
|
+
import { revokedIntentIds, revocationId, staleRevocationIds } from '#agency/revocation'
|
|
42
|
+
import {
|
|
43
|
+
CONSEQUENCE_TYPE, CONSEQUENCE_TTL_TICKS,
|
|
44
|
+
consequenceEntity, fnv1a, paramsKey,
|
|
45
|
+
} from '#agency/consequence'
|
|
41
46
|
|
|
42
|
-
/** Ticks an async (communicate/external) intent may stay 'awaiting' before it is
|
|
43
|
-
|
|
47
|
+
/** Ticks an async (communicate/external) intent may stay 'awaiting' before it is
|
|
48
|
+
* abandoned. Exported: the ReafferenceEngine's sensory-confirmation path (P5)
|
|
49
|
+
* stands down at this boundary so the executor's timeout-failure wins. */
|
|
50
|
+
export const AWAIT_TIMEOUT = 15
|
|
44
51
|
|
|
45
52
|
/** Map a communicate schema to the ProactiveCommunicator effector + the permission name. */
|
|
46
53
|
const COMM_SCHEMA_TO_EFFECTOR: Record<string, string> = {
|
|
@@ -134,15 +141,48 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
134
141
|
const del: string[] = []
|
|
135
142
|
const metrics: Array<[ string, number ]> = []
|
|
136
143
|
|
|
137
|
-
const energy = state.metrics.get(
|
|
138
|
-
const stress = state.metrics.get(
|
|
144
|
+
const energy = state.metrics.get('energy.level') ?? 100
|
|
145
|
+
const stress = state.metrics.get('stress.load' ) ?? 0
|
|
146
|
+
|
|
147
|
+
// ── Expire consequence descriptors (EXAFFERENCE P1) ──────────
|
|
148
|
+
// Descriptors deliberately outlive intent resolution (the sensory echo of a
|
|
149
|
+
// reconciled action still arrives); their only cleanup is this TTL sweep.
|
|
150
|
+
for( const [ id, e ] of state.entities ){
|
|
151
|
+
if( e.type !== CONSEQUENCE_TYPE ) continue
|
|
152
|
+
if( tick >= num( e.metadata?.['expiresAt'], 0 ) ) del.push( id )
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Revocation tombstones (EXAFFERENCE P4) ───────────────────
|
|
156
|
+
// Reap expired tombstones (intent vanished otherwise), and collect live ones
|
|
157
|
+
// so the selected-processing loop can refuse the half-race case: Deliberation
|
|
158
|
+
// committed `selected` the same tick the tombstone was written (both read the
|
|
159
|
+
// pre-tombstone snapshot), so the intent surfaces here still needing to die.
|
|
160
|
+
del.push( ...staleRevocationIds( state.entities, tick ) )
|
|
161
|
+
const revoked = revokedIntentIds( state.entities, tick )
|
|
162
|
+
|
|
163
|
+
// A tombstoned intent dies whatever its status — including an 'expanding'
|
|
164
|
+
// composite parent preempted mid-routine (registry #4) — and takes its
|
|
165
|
+
// sub-intents with it, in any state ('selected' queued by the executor's
|
|
166
|
+
// own in-tick advance, or 'awaiting' a host). The selected-loop guard below
|
|
167
|
+
// additionally prevents enacting any of them this tick.
|
|
168
|
+
if( revoked.size > 0 )
|
|
169
|
+
for( const [ id, e ] of state.entities ){
|
|
170
|
+
if( e.type !== 'agency.intent') continue
|
|
171
|
+
const parentId = str( e.metadata?.['parentIntentId'] )
|
|
172
|
+
if( revoked.has( id ) ) del.push( id, revocationId( id ) )
|
|
173
|
+
else if( parentId && revoked.has( parentId ) ) del.push( id )
|
|
174
|
+
}
|
|
139
175
|
|
|
140
176
|
// ── Timeout stranded async intents ───────────────────────────
|
|
141
177
|
// An 'awaiting' intent whose host/delivery never returned would block the
|
|
142
178
|
// serial Will forever. After AWAIT_TIMEOUT ticks, abandon it as a failed
|
|
143
179
|
// outcome (which also teaches reafference the action is unreliable here).
|
|
144
180
|
for( const [ id, e ] of state.entities ){
|
|
145
|
-
if( e.type !== 'agency.intent' || str( e.metadata?.['status'] ) !== 'awaiting'
|
|
181
|
+
if( e.type !== 'agency.intent' || str( e.metadata?.['status'] ) !== 'awaiting') continue
|
|
182
|
+
// POLICY_REAFFERENCE P4 — an escalated intent is HELD: the stem owns its
|
|
183
|
+
// lifecycle (extended TTL → approve/deny/expire), so the executor must not
|
|
184
|
+
// time it out at AWAIT_TIMEOUT and reconcile it as a phantom failure.
|
|
185
|
+
if( e.metadata?.['escalated'] === true ) continue
|
|
146
186
|
const dispatchedAt = num( e.metadata?.['dispatchedAt'], tick )
|
|
147
187
|
if( tick - dispatchedAt < AWAIT_TIMEOUT ) continue
|
|
148
188
|
|
|
@@ -160,17 +200,22 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
160
200
|
this._emitEnacted( intent, timedOut, predicted, tick )
|
|
161
201
|
if( intent.planId && intent.planStepId )
|
|
162
202
|
this._emitActionOutcome( intent, false, 0, 1, tick )
|
|
163
|
-
logger.info(
|
|
203
|
+
logger.info(`[motor] ⏱ "${ intent.schema }" timed out after ${ tick - dispatchedAt } ticks`)
|
|
164
204
|
}
|
|
165
205
|
|
|
166
206
|
// Process committed intents in a stable order (determinism / replay).
|
|
167
207
|
const selected = [ ...state.entities.entries() ]
|
|
168
|
-
.filter( ( [ , e ] ) => e.type === 'agency.intent' && str( e.metadata?.['status'] ) === 'selected'
|
|
208
|
+
.filter( ( [ , e ] ) => e.type === 'agency.intent' && str( e.metadata?.['status'] ) === 'selected')
|
|
169
209
|
.sort( ( a, b ) => ( a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0 ) )
|
|
170
210
|
|
|
171
211
|
let enactedCount = 0
|
|
172
212
|
|
|
173
213
|
for( const [ id, e ] of selected ){
|
|
214
|
+
// Revoked mid-commit (P4), or a sub of a preempted composite (#4) — refuse
|
|
215
|
+
// to enact; the sweep above already queued the deletes.
|
|
216
|
+
if( revoked.has( id ) ) continue
|
|
217
|
+
const parentOf = str( e.metadata?.['parentIntentId'] )
|
|
218
|
+
if( parentOf && revoked.has( parentOf ) ) continue
|
|
174
219
|
const intent = readIntent( id, e.metadata )
|
|
175
220
|
const schema = this._resolve( intent.schema )
|
|
176
221
|
|
|
@@ -190,7 +235,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
190
235
|
: { mode: 'external', success: true, outcomeQuality: 0.5, valence: 0,
|
|
191
236
|
description: `Unknown schema "${ intent.schema }" routed to the host.` }
|
|
192
237
|
|
|
193
|
-
if( enaction.mode === 'sync'
|
|
238
|
+
if( enaction.mode === 'sync'){
|
|
194
239
|
set.push( outcomeEntity( tick, intent, enaction, predicted ) )
|
|
195
240
|
del.push( id )
|
|
196
241
|
if( enaction.metricDeltas ) metrics.push( ...enaction.metricDeltas )
|
|
@@ -224,6 +269,26 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
224
269
|
predictedValence: predicted.expectedValence,
|
|
225
270
|
},
|
|
226
271
|
})
|
|
272
|
+
// EXAFFERENCE P1 — the dispatched action's expected sensory footprint,
|
|
273
|
+
// so the world's answer can be recognized as ours when it arrives
|
|
274
|
+
// through the senses (P2). Host acks correlate by intent id already.
|
|
275
|
+
// For a communicate whose words are authored, also carry the text so an
|
|
276
|
+
// echo of them can be matched (P2) and, if the intent is still awaiting,
|
|
277
|
+
// confirm it through the senses (P5) instead of timing out as a failure.
|
|
278
|
+
const awaitingText = enaction.mode === 'communicate'
|
|
279
|
+
? ( str( intent.parameters['content'] ) ?? firstMessage( intent.parameters['messages'] ) )
|
|
280
|
+
: undefined
|
|
281
|
+
set.push( consequenceEntity({
|
|
282
|
+
intentId: id, schema: intent.schema,
|
|
283
|
+
mode: enaction.mode === 'communicate' ? 'communicate' : 'external',
|
|
284
|
+
...( enaction.mode === 'communicate'
|
|
285
|
+
? { effector: COMM_SCHEMA_TO_EFFECTOR[ intent.schema ] ?? intent.schema }
|
|
286
|
+
: {} ),
|
|
287
|
+
...( intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {} ),
|
|
288
|
+
...( awaitingText ? { text: awaitingText, textHash: fnv1a( awaitingText ) } : {} ),
|
|
289
|
+
paramsHash: fnv1a( paramsKey( intent.parameters ) ),
|
|
290
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS, tick,
|
|
291
|
+
}) )
|
|
227
292
|
this._emitDispatch( intent, enaction.mode, tick )
|
|
228
293
|
metrics.push([ enaction.mode === 'communicate'
|
|
229
294
|
? 'agency.communicate.dispatched'
|
|
@@ -253,7 +318,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
253
318
|
metadata: { ...meta, status: 'expanding', steps, cursor: 0, accumQuality: 0, accumValence: 0, completed: 0 },
|
|
254
319
|
})
|
|
255
320
|
set.push( this._subIntent( parentId, intent.targetEntityId, intent.parameters, steps[0]!, 0, tick ) )
|
|
256
|
-
logger.info(
|
|
321
|
+
logger.info(`[motor] composite "${ intent.schema }" → ${ steps.length } steps`)
|
|
257
322
|
}
|
|
258
323
|
|
|
259
324
|
private _advance(
|
|
@@ -380,7 +445,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
380
445
|
if( bubbles.length === 0 && this._author ){
|
|
381
446
|
const name = str( intent.parameters['targetEntityName'] ) ?? intent.targetEntityId ?? 'them'
|
|
382
447
|
try { bubbles = await this._author.authorOutreach( intent.targetEntityId ?? '', name, str( intent.parameters['gist'] ) ) }
|
|
383
|
-
catch( err ){ logger.warn(
|
|
448
|
+
catch( err ){ logger.warn(`[motor] outreach authoring failed: ${ errMsg( err ) }`) }
|
|
384
449
|
}
|
|
385
450
|
if( bubbles.length === 0 ) return false // nothing authored to send → await
|
|
386
451
|
|
|
@@ -394,13 +459,24 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
394
459
|
}
|
|
395
460
|
let result: ActionResult
|
|
396
461
|
try { result = await this._comms.executeAction( request, state ) }
|
|
397
|
-
catch( err ){ logger.warn(
|
|
462
|
+
catch( err ){ logger.warn(`[motor] communicate delivery failed: ${ errMsg( err ) }`); return false }
|
|
398
463
|
|
|
399
464
|
if( result.commands.set?.length ) set.push( ...result.commands.set )
|
|
400
465
|
const out: Enaction = { mode: 'communicate', success: result.success,
|
|
401
466
|
outcomeQuality: result.feedback.outcomeQuality, valence: 0, description: result.description }
|
|
402
467
|
set.push( outcomeEntity( tick, intent, out, predicted ) )
|
|
403
468
|
del.push( id )
|
|
469
|
+
// EXAFFERENCE P1 — the delivered words' sensory footprint: the channel echo
|
|
470
|
+
// or a quote-back of this exact text should read as ours, not as the world
|
|
471
|
+
// surprising us (P2 matches on the content hash).
|
|
472
|
+
if( result.success )
|
|
473
|
+
set.push( consequenceEntity({
|
|
474
|
+
intentId: id, schema: intent.schema, mode: 'communicate', effector,
|
|
475
|
+
...( intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {} ),
|
|
476
|
+
textHash: fnv1a( bubbles.join('\n') ),
|
|
477
|
+
text: bubbles.join('\n'),
|
|
478
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS, tick,
|
|
479
|
+
}) )
|
|
404
480
|
this._emitEnacted( intent, out, predicted, tick )
|
|
405
481
|
this._emitActionOutcome( intent, result.success, result.feedback.outcomeQuality,
|
|
406
482
|
clamp01( Math.abs( predicted.expectedReward - result.feedback.outcomeQuality ) ), tick )
|
|
@@ -420,7 +496,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
420
496
|
payload: { schema: intent.schema, success: enaction.success, outcomeQuality: enaction.outcomeQuality, surprise, tick },
|
|
421
497
|
})
|
|
422
498
|
}
|
|
423
|
-
catch( err ){ logger.warn(
|
|
499
|
+
catch( err ){ logger.warn(`[motor] enacted publish failed: ${ errMsg( err ) }`) }
|
|
424
500
|
}
|
|
425
501
|
|
|
426
502
|
/**
|
|
@@ -452,7 +528,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
452
528
|
},
|
|
453
529
|
})
|
|
454
530
|
}
|
|
455
|
-
catch( err ){ logger.warn(
|
|
531
|
+
catch( err ){ logger.warn(`[motor] action outcome publish failed: ${ errMsg( err ) }`) }
|
|
456
532
|
}
|
|
457
533
|
|
|
458
534
|
private _emitDispatch( intent: Intent, mode: 'communicate' | 'external', tick: Tick ): void {
|
|
@@ -469,7 +545,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
|
|
|
469
545
|
},
|
|
470
546
|
})
|
|
471
547
|
}
|
|
472
|
-
catch( err ){ logger.warn(
|
|
548
|
+
catch( err ){ logger.warn(`[motor] dispatch publish failed: ${ errMsg( err ) }`) }
|
|
473
549
|
}
|
|
474
550
|
}
|
|
475
551
|
|