@mindot/will 0.8.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 +6985 -3337
- package/dist/index.js.map +1 -1
- package/dist/surface/channels/discord.d.ts +177 -0
- package/dist/surface/channels/discord.js +394 -0
- 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 +11 -5
- package/dist/surface/channels/whatsapp.js.map +1 -0
- package/dist/{cli.js → surface/cli.js} +5382 -1573
- 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-cS6k4uiJ.d.ts → will-evj9_vrd.d.ts} +6658 -5078
- package/package.json +11 -12
- package/src/cognition/agency/consequence.ts +356 -1
- package/src/cognition/agency/conversation.aim.ts +292 -0
- package/src/cognition/agency/engines/action.selector.ts +142 -5
- package/src/cognition/agency/engines/affordance.synthesizer.ts +200 -7
- package/src/cognition/agency/engines/deliberation.engine.ts +76 -3
- package/src/cognition/agency/engines/motor.schema.executor.ts +509 -32
- package/src/cognition/agency/engines/reafference.engine.ts +160 -4
- package/src/cognition/agency/execution.primitives.ts +17 -4
- package/src/cognition/agency/proactive.communicator.ts +19 -3
- package/src/cognition/agency/reconcile.learning.ts +5 -4
- package/src/cognition/agency/restart.ts +66 -0
- 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 +49 -0
- package/src/cognition/agency/settlement.ts +203 -0
- package/src/cognition/agency/types.ts +73 -1
- package/src/cognition/cache/composition.ts +232 -0
- package/src/cognition/cache/deliberation.cache.ts +219 -0
- package/src/cognition/cache/fingerprint.ts +120 -0
- package/src/cognition/cache/types.ts +105 -0
- package/src/cognition/config.mirror.entities.ts +108 -1
- package/src/cognition/event.schemas.ts +22 -8
- package/src/cognition/faculties/affective.blender.ts +21 -4
- package/src/cognition/faculties/autobiographical.narrator.ts +5 -10
- package/src/cognition/faculties/circadian.oscillator.ts +36 -7
- package/src/cognition/faculties/episodic.consolidator.ts +59 -3
- package/src/cognition/faculties/executive.engine/action.record.ts +129 -0
- package/src/cognition/faculties/executive.engine/commands.ts +189 -14
- package/src/cognition/faculties/executive.engine/context.ts +106 -46
- package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +1 -1
- package/src/cognition/faculties/executive.engine/engine.ts +714 -136
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +230 -45
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +320 -65
- package/src/cognition/faculties/executive.engine/facet.ts +81 -26
- package/src/cognition/faculties/executive.engine/gating.ts +14 -14
- package/src/cognition/faculties/executive.engine/parser.ts +120 -38
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +331 -38
- package/src/cognition/faculties/executive.engine/types.ts +84 -12
- package/src/cognition/faculties/exteroception.ts +99 -98
- package/src/cognition/faculties/goal.manager.ts +144 -16
- package/src/cognition/faculties/known.entity.tracker.ts +287 -29
- package/src/cognition/faculties/moral.evaluator.ts +8 -3
- package/src/cognition/faculties/persona.consolidator.ts +141 -0
- 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/reputation.tracker.ts +66 -2
- package/src/cognition/faculties/self.model.updater.ts +19 -12
- package/src/cognition/faculties/semantic.engine/integrator.ts +1 -1
- package/src/cognition/faculties/social.perception.ts +47 -3
- package/src/cognition/faculties/threat.evaluator.ts +7 -0
- package/src/cognition/faculties/working.memory.ts +16 -21
- package/src/cognition/identity.entity.ts +205 -0
- package/src/cognition/index.ts +7 -0
- package/src/cognition/instruction.handler.ts +1 -1
- package/src/cognition/memory/vector.adapter.ts +12 -3
- package/src/cognition/memory/vector.embedder.ts +45 -4
- package/src/cognition/percept.entity.ts +122 -0
- package/src/cognition/persona.prior.ts +6 -0
- package/src/cognition/sense.boundary.ts +176 -0
- package/src/cognition/senses/audition.engine/engine.ts +492 -53
- package/src/cognition/senses/base.sense.engine.ts +105 -7
- package/src/cognition/senses/index.ts +83 -13
- package/src/cognition/senses/provenance.ts +128 -0
- package/src/cognition/senses/somatosensation.engine.ts +117 -9
- package/src/cognition/social.identity.ts +296 -0
- package/src/cognition/utilities/token.tracker.ts +94 -10
- package/src/core/orchestrator.ts +51 -0
- package/src/index.ts +39 -5
- package/src/llm/gate.ts +48 -0
- package/src/llm/index.ts +127 -33
- package/src/llm/routing.ts +6 -0
- package/src/llm/summarizer.ts +1 -1
- package/src/llm/wire.contracts.ts +57 -0
- package/src/pma/index.ts +68 -54
- package/src/stem/assembly.audit.ts +1 -0
- package/src/stem/guards/identity.coherence.ts +1 -1
- package/src/stem/index.ts +171 -23
- package/src/stem/mind.ts +198 -57
- 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/outbox.writer.ts +40 -2
- 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/surface/channels/discord.ts +609 -0
- package/src/{channels → surface/channels}/roster.ts +1 -1
- package/src/surface/channels/types.ts +136 -0
- package/src/{channels → surface/channels}/whatsapp.ts +22 -10
- package/src/{cli.ts → surface/cli.ts} +14 -9
- 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 +194 -33
- package/src/{serve → surface/serve}/server.ts +11 -4
- package/src/types.ts +24 -3
- package/dist/channels/discord.d.ts +0 -69
- package/dist/channels/discord.js +0 -193
- 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/channels/discord.ts +0 -214
- package/src/channels/types.ts +0 -46
- package/src/cognition/faculties/executive.engine/messages.ts +0 -102
- 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
|
@@ -31,6 +31,11 @@ import type { SchemaRepertoire } from '#agency/schemas/repertoire'
|
|
|
31
31
|
import { schemaEntityId, availabilityEntityId } from '#agency/schemas/repertoire'
|
|
32
32
|
import { asFinality } from '#stem/policy/arbiter'
|
|
33
33
|
import { AWAIT_TIMEOUT } from '#agency/engines/motor.schema.executor'
|
|
34
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
35
|
+
import { asProvenance } from '#senses/provenance'
|
|
36
|
+
import {
|
|
37
|
+
SENT_TYPE, DEFAULT_REPLY_WINDOW_TICKS, resolveReplyExpectations,
|
|
38
|
+
} from '#agency/conversation.aim'
|
|
34
39
|
|
|
35
40
|
const PROC_THRESHOLD = 0.60 // mirror of repertoire's threshold for the habitual-count metric
|
|
36
41
|
|
|
@@ -81,6 +86,11 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
81
86
|
// action.outcome the PlanningEngine advances on. (The executor is the emitter
|
|
82
87
|
// for sync/timeout outcomes; this is its async counterpart — one emitter each.)
|
|
83
88
|
{ type: 'action.outcome', version: 1, validate: () => null },
|
|
89
|
+
// Whether a person answers the mind when it speaks to them. Distinct from
|
|
90
|
+
// `interaction.occurred`, which reports something someone DID — a silence is
|
|
91
|
+
// not an act and so can never appear there, which is why "they never answer
|
|
92
|
+
// me" was unlearnable despite `socialStanding` being built to carry it.
|
|
93
|
+
{ type: 'social.responsiveness', version: 1, validate: () => null },
|
|
84
94
|
]
|
|
85
95
|
}
|
|
86
96
|
/** Creation seam: register a composite proposed by the executive/deliberation facet. */
|
|
@@ -152,7 +162,11 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
152
162
|
for( const [ , e ] of state.entities ){
|
|
153
163
|
if( e.type !== 'percept') continue
|
|
154
164
|
const m = ( e.metadata ?? {} ) as Record<string, unknown>
|
|
155
|
-
|
|
165
|
+
// asProvenance(), not a literal compare: this is an untyped read out of
|
|
166
|
+
// entity metadata, exactly what that normalizer exists for. Behaviour is
|
|
167
|
+
// unchanged — absent and garbage both normalize to 'exafferent', which
|
|
168
|
+
// fails this test the same way `str()` returning undefined did.
|
|
169
|
+
if( asProvenance( m['provenance'] ) !== 'reafferent') continue
|
|
156
170
|
const iid = str( m['sourceIntentId'] )
|
|
157
171
|
if( !iid || gradedIntentIds.has( iid ) || sensedIntentIds.has( iid ) ) continue
|
|
158
172
|
const aw = awaiting.get( iid )
|
|
@@ -192,6 +206,7 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
192
206
|
let updates = 0
|
|
193
207
|
let discovered = 0
|
|
194
208
|
let refused = 0
|
|
209
|
+
let withheld = 0
|
|
195
210
|
for( const { id, meta: m, fromState } of outcomes ){
|
|
196
211
|
const schema = str( m['schema'] )
|
|
197
212
|
if( !schema ){ if( fromState ) del.push( id ); continue }
|
|
@@ -201,6 +216,25 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
201
216
|
// habit, param priors), or the Will learns it is unskilled at something it
|
|
202
217
|
// is merely forbidden to do. The awaiting intent is still freed, and a
|
|
203
218
|
// refused plan step is signalled unsuccessful so the plan doesn't hang.
|
|
219
|
+
// Chosen silence. The mind considered speaking and decided not to, which
|
|
220
|
+
// is a decision — not a failure, and not a refusal either: nothing forbade
|
|
221
|
+
// it, so availability must not be dented and `recordRefusal` must not run.
|
|
222
|
+
// Free the intent, signal any plan step, and teach NOTHING: the question
|
|
223
|
+
// was never whether it can speak.
|
|
224
|
+
//
|
|
225
|
+
// Before this, a declined outreach timed out at AWAIT_TIMEOUT and folded
|
|
226
|
+
// into `reach-out`'s competence as a failure — the mind learning it is bad
|
|
227
|
+
// at speaking from the times it chose not to speak.
|
|
228
|
+
if( m['withheld'] === true ){
|
|
229
|
+
if( fromState ) del.push( id )
|
|
230
|
+
const heldIntent = str( m['intentId'] )
|
|
231
|
+
if( heldIntent ) del.push( heldIntent )
|
|
232
|
+
const heldPlan = str( m['planId'] )
|
|
233
|
+
if( heldPlan ) this._emitPlanOutcome( heldPlan, str( m['stepId'] ), schema, false, 0, 0, tick )
|
|
234
|
+
withheld++
|
|
235
|
+
continue
|
|
236
|
+
}
|
|
237
|
+
|
|
204
238
|
if( m['refused'] === true ){
|
|
205
239
|
const finality = asFinality( m['finality'] )
|
|
206
240
|
|
|
@@ -242,13 +276,13 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
242
276
|
updates++
|
|
243
277
|
|
|
244
278
|
// Plan advancement for the async path: a host-acked outcome that carries plan
|
|
245
|
-
//
|
|
279
|
+
// the plan link is the ONLY signal the PlanningEngine will get (the executor never
|
|
246
280
|
// saw the ack — the intent was 'awaiting'). Emit the action.outcome it advances
|
|
247
281
|
// on. Sync/timeout outcomes never carry planId here (the executor emitted their
|
|
248
282
|
// action.outcome already), so this never double-advances.
|
|
249
283
|
const planId = str( m['planId'] )
|
|
250
284
|
if( planId )
|
|
251
|
-
this._emitPlanOutcome( planId, str( m['stepId'] ), schema, m['success'] === true, num( m['outcomeQuality'], 0 ), num( m['surprise'], 0 ), tick )
|
|
285
|
+
this._emitPlanOutcome( planId, str( m['stepId'] ), schema, m['success'] === true, num( m['outcomeQuality'], 0 ), num( m['surprise'], 0 ), tick, str( m['description'] ) )
|
|
252
286
|
|
|
253
287
|
// Discovery: the first time the Will enacts a schema, it becomes a known part
|
|
254
288
|
// of its repertoire (the new model's "discovered" — earned by doing, not catalogued).
|
|
@@ -281,6 +315,19 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
281
315
|
// Availability entries (P2) mirror the same way — empty until a refusal lands.
|
|
282
316
|
for( const e of this._repertoire.availabilityEntities() ) set.push( e )
|
|
283
317
|
|
|
318
|
+
// ── 3.5 Did the words achieve what they were for? ────────────
|
|
319
|
+
// The motor loop above graded whether each act EXECUTED. For a communicative
|
|
320
|
+
// act that is the smaller half of the question: the outbox accepting a message
|
|
321
|
+
// is not the world answering it. Both were the same fact until now, which is
|
|
322
|
+
// how `reach-out` came to sit at 28 enactments / 28 successes while the person
|
|
323
|
+
// it kept reaching had said nothing back.
|
|
324
|
+
//
|
|
325
|
+
// Folded here rather than in a new engine because this is the same question
|
|
326
|
+
// this engine already exists to ask, one layer out — reafference over a social
|
|
327
|
+
// act instead of a motor one. The resolution itself is pure (conversation.aim);
|
|
328
|
+
// all that happens here is writing it down and saying it out loud.
|
|
329
|
+
const replied = this._resolveReplies( tick, state, set )
|
|
330
|
+
|
|
284
331
|
// ── 4. Telemetry ─────────────────────────────────────────────
|
|
285
332
|
const skills = this._repertoire.skills()
|
|
286
333
|
const habitual = [ ...skills.values() ].filter( s => s.habitStrength >= PROC_THRESHOLD ).length
|
|
@@ -291,13 +338,112 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
291
338
|
[ 'agency.habitual.count', habitual ],
|
|
292
339
|
[ 'agency.sensory.confirmed', sensory ],
|
|
293
340
|
)
|
|
341
|
+
// Quiet path stays byte-identical: a Will that has spoken to nobody, or whose
|
|
342
|
+
// every turn was answered, writes nothing here (cf. EXAFFERENCE P3).
|
|
343
|
+
if( replied.answered > 0 ) metrics.push([ 'social.answered.count', replied.answered ])
|
|
344
|
+
if( replied.unanswered > 0 ) metrics.push([ 'social.unanswered.count', replied.unanswered ])
|
|
294
345
|
// Only emit the refusal metric when it fired — a never-refused Will writes
|
|
295
346
|
// nothing here, preserving the byte-identical quiet path (cf. EXAFFERENCE P3).
|
|
296
347
|
if( refused > 0 ) metrics.push([ 'agency.refused.count', refused ])
|
|
348
|
+
// Counted separately from refusals on purpose: one is the world saying no,
|
|
349
|
+
// the other is the mind saying not now. Collapsing them would read as a
|
|
350
|
+
// policy problem in the telemetry when nothing was forbidden.
|
|
351
|
+
if( withheld > 0 ) metrics.push([ 'agency.withheld.count', withheld ])
|
|
297
352
|
|
|
298
353
|
return { commands: { set, delete: del, metrics } }
|
|
299
354
|
}
|
|
300
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Latch each open turn's fate onto its own record and announce it once.
|
|
358
|
+
*
|
|
359
|
+
* Two rules earn their keep here:
|
|
360
|
+
*
|
|
361
|
+
* • MERGE, never replace. `StateManager.setEntity` overwrites the whole entity,
|
|
362
|
+
* and a `conversation.sent` carries `outboxMessageIds` — the sole key by which
|
|
363
|
+
* a later delivery ack can find it. Rewriting the record with only the fields
|
|
364
|
+
* this method cares about would sever that, silently, for every turn that got
|
|
365
|
+
* an answer.
|
|
366
|
+
*
|
|
367
|
+
* • Latch, don't recompute. `answeredAt`/`unansweredAt` persist, so the event
|
|
368
|
+
* fires on the one tick the fact changed rather than every tick for the rest
|
|
369
|
+
* of the session — which for an unanswered turn would be thousands of
|
|
370
|
+
* identical reputation hits against one person for one silence.
|
|
371
|
+
*/
|
|
372
|
+
private _resolveReplies(
|
|
373
|
+
tick: Tick,
|
|
374
|
+
state: ReadonlySimulationState,
|
|
375
|
+
set: EntityInput[],
|
|
376
|
+
): { answered: number; unanswered: number } {
|
|
377
|
+
// A trait, not a constant: how long a silence takes to mean something differs
|
|
378
|
+
// between minds, so it tunes through the persona prior like every other
|
|
379
|
+
// developable parameter. Absent ⇒ the default ⇒ the pre-seam behaviour.
|
|
380
|
+
//
|
|
381
|
+
// Read from the SELECTOR's config despite being applied here, because it and
|
|
382
|
+
// `repeatWindowTicks` are two readings of one disposition — how long this mind
|
|
383
|
+
// sits with something it has said. Held apart, a mind could tune itself into
|
|
384
|
+
// saying a thing again while still calling the silence too fresh to count.
|
|
385
|
+
const window = Math.max(
|
|
386
|
+
1,
|
|
387
|
+
Math.round(
|
|
388
|
+
readEffectiveParams( state, 'engine-config-action-selector').replyWindowTicks
|
|
389
|
+
?? DEFAULT_REPLY_WINDOW_TICKS
|
|
390
|
+
),
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
const { answered, unanswered } = resolveReplyExpectations( state.entities, tick, window )
|
|
394
|
+
if( answered.length === 0 && unanswered.length === 0 ) return { answered: 0, unanswered: 0 }
|
|
395
|
+
|
|
396
|
+
const merge = ( id: string, patch: Record<string, unknown> ): void => {
|
|
397
|
+
const existing = state.entities.get( id )
|
|
398
|
+
if( !existing ) return
|
|
399
|
+
set.push({
|
|
400
|
+
id, type: SENT_TYPE,
|
|
401
|
+
metadata: { ...( existing.metadata as Record<string, unknown> ?? {} ), ...patch },
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
for( const { turn, at, with: said } of answered ){
|
|
406
|
+
// Their words, not merely the fact of them — see SpokenTurn.answeredWith.
|
|
407
|
+
merge( turn.entityId, { answeredAt: at, ...( said ? { answeredWith: said } : {} ) } )
|
|
408
|
+
this._emitResponsiveness( turn.targetEntityId, true, at - turn.tick, tick )
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
for( const turn of unanswered ){
|
|
412
|
+
merge( turn.entityId, { unansweredAt: tick } )
|
|
413
|
+
this._emitResponsiveness( turn.targetEntityId, false, tick - turn.tick, tick )
|
|
414
|
+
logger.info(
|
|
415
|
+
`[reafference] no answer from ${ turn.targetEntityName ?? turn.targetEntityId } ` +
|
|
416
|
+
`after ${ tick - turn.tick } ticks — "${ turn.preview.slice( 0, 60 ) }"`
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return { answered: answered.length, unanswered: unanswered.length }
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Publish how a person responded to being spoken to.
|
|
425
|
+
*
|
|
426
|
+
* Deliberately NOT an `interaction.occurred`: that event means "someone did
|
|
427
|
+
* something toward us" and carries a valence for what they did. A silence is
|
|
428
|
+
* nobody doing anything, and forcing it through that channel would have the
|
|
429
|
+
* ReputationTracker book a hostile *act* where there was only an absence — the
|
|
430
|
+
* mind would come to think it was being rebuffed rather than simply not
|
|
431
|
+
* answered yet. Separate signal, separate meaning, one consumer decides what
|
|
432
|
+
* either is worth.
|
|
433
|
+
*/
|
|
434
|
+
private _emitResponsiveness( keid: string, answered: boolean, waitedTicks: number, tick: Tick ): void {
|
|
435
|
+
if( !this._bus ) return
|
|
436
|
+
try {
|
|
437
|
+
this._bus.publish({
|
|
438
|
+
type: 'social.responsiveness', version: 1, sourceEngine: this.name,
|
|
439
|
+
// An answer is ordinary; being ignored is the one worth interrupting for.
|
|
440
|
+
salience: answered ? 0.3 : 0.55,
|
|
441
|
+
payload: { keid, answered, waitedTicks, tick },
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
catch( err ){ logger.warn(`[reafference] responsiveness publish failed: ${ err instanceof Error ? err.message : String( err ) }`) }
|
|
445
|
+
}
|
|
446
|
+
|
|
301
447
|
private _emitProceduralized( skill: LearnedSkill, tick: Tick ): void {
|
|
302
448
|
if( !this._bus ) return
|
|
303
449
|
try {
|
|
@@ -318,6 +464,9 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
318
464
|
private _emitPlanOutcome(
|
|
319
465
|
planId: string, stepId: string | undefined, schema: string,
|
|
320
466
|
success: boolean, outcomeQuality: number, surprise: number, tick: Tick,
|
|
467
|
+
/** The host's own words for what happened. Absent on withheld/refused paths,
|
|
468
|
+
* where there was no host and nothing to say beyond the fate. */
|
|
469
|
+
description?: string,
|
|
321
470
|
): void {
|
|
322
471
|
if( !this._bus ) return
|
|
323
472
|
try {
|
|
@@ -326,7 +475,14 @@ export class ReafferenceEngine implements CognitiveEngine {
|
|
|
326
475
|
salience: Math.min( 1, outcomeQuality * 0.6 ),
|
|
327
476
|
payload: {
|
|
328
477
|
actionType: schema, domain: schema, success, outcomeQuality, surprise,
|
|
329
|
-
|
|
478
|
+
// The host's own words for what happened, not a stock sentence. This
|
|
479
|
+
// hardcoded `'The world confirmed the action.'` — and since
|
|
480
|
+
// `action.record` is built from this payload, that phrase (or nothing,
|
|
481
|
+
// from the executor's side) is ALL the prompt's `## Recent Action
|
|
482
|
+
// Outcomes` ever showed. The `agency.outcome` entity has carried the
|
|
483
|
+
// real description the whole time (`reconcile.learning.ts:89`); it was
|
|
484
|
+
// read here as `m['description']` and dropped on the floor.
|
|
485
|
+
description: description ?? ( success ? 'The world confirmed the action.' : 'The world rejected the action.'),
|
|
330
486
|
planId,
|
|
331
487
|
...( stepId ? { stepId } : {} ),
|
|
332
488
|
tick,
|
|
@@ -95,10 +95,23 @@ function syncStance( ctx: EnactionContext ): Enaction {
|
|
|
95
95
|
return sync( 0.5, 0.0, 'I let time pass; regulatory processes continue their quiet work.')
|
|
96
96
|
case 'express':
|
|
97
97
|
return sync( 0.6, 0.1, 'My inner state becomes outwardly visible.')
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
// No `inspect` case, deliberately.
|
|
99
|
+
//
|
|
100
|
+
// Looking is now outward ONLY — a question put to the world, tagged external
|
|
101
|
+
// and dispatched. Turning attention inward already has three names on this
|
|
102
|
+
// very floor: `orient` sweeps the situation, `attend` mobilises attention,
|
|
103
|
+
// `reflect` turns inward and lets patterns settle. `inspect` naming that too
|
|
104
|
+
// was a second name for an act that already had one.
|
|
105
|
+
//
|
|
106
|
+
// The cost of the collision was not stylistic. The two readings have
|
|
107
|
+
// DIFFERENT failure modes — "I hold no record of it" versus "the world did not
|
|
108
|
+
// answer" — and one verb covering both meant a pure function needed three
|
|
109
|
+
// flags passed in to tell which it was. Live, the inward reading could not
|
|
110
|
+
// fail at all: a fresh Will proceduralized inspect to habit 0.64 in fifteen
|
|
111
|
+
// ticks, examining its own affordance entities and being told it went well.
|
|
112
|
+
//
|
|
113
|
+
// Outward-only, that is structurally impossible rather than conditionally
|
|
114
|
+
// caught. An unanswered look fails because nothing answered.
|
|
102
115
|
default:
|
|
103
116
|
return sync( 0.5, 0.0, `I enact ${ schema.id }.`)
|
|
104
117
|
}
|
|
@@ -190,7 +190,17 @@ export class ProactiveCommunicator {
|
|
|
190
190
|
// Generate outbox message IDs first so we can embed them in conversation.sent
|
|
191
191
|
// and correlate deliveries back to this intent (TODO 11.3).
|
|
192
192
|
const originalMessage = ( request.parameters?.originalMessage as string ) ?? ''
|
|
193
|
-
|
|
193
|
+
// `decidedAt` is the enacting tick and is always set by the caller; the
|
|
194
|
+
// `parameters.tick` fallback is for hosts that build a request by hand.
|
|
195
|
+
//
|
|
196
|
+
// This defaulted to 0 for every agency-path delivery, because MotorSchemaExecutor
|
|
197
|
+
// builds `parameters` from the intent and never put a tick in it. Two
|
|
198
|
+
// consequences, both silent: every `conversation.sent` was stamped tick 0, so
|
|
199
|
+
// anything comparing against it (satiation, undertaking discharge) compared
|
|
200
|
+
// against zero and never fired; and the id `conv-sent-<target>-0` was CONSTANT,
|
|
201
|
+
// so each send to a person overwrote the record of the last one — the mind kept
|
|
202
|
+
// exactly one memory of having spoken to each person, forever.
|
|
203
|
+
const deliveryTick = ( request.parameters?.tick as number ) ?? request.decidedAt ?? 0
|
|
194
204
|
const replyToMessageId = ( request.parameters?.replyToMessageId as string ) ?? undefined
|
|
195
205
|
const isAck = ( request.parameters?.isAck as boolean ) ?? false
|
|
196
206
|
|
|
@@ -264,9 +274,15 @@ export class ProactiveCommunicator {
|
|
|
264
274
|
description: `I reach out to ${targetEntityName}: "${fullReply.slice( 0, 80 )}${fullReply.length > 80 ? '…' : ''}"`,
|
|
265
275
|
commands,
|
|
266
276
|
feedback: {
|
|
267
|
-
|
|
277
|
+
// NOT a success yet. This reports the TRANSPORT, and the act's point is to be
|
|
278
|
+
// answered — an outcome not yet known at this moment. Scoring delivery as 0.85
|
|
279
|
+
// taught the mind that reaching out works every time, including the times it
|
|
280
|
+
// was ignored, which is why it re-asked the same question 19 times in two
|
|
281
|
+
// minutes. Neutral here; the unanswered/answered signal in outreach.silence.ts
|
|
282
|
+
// is what actually moves the pull toward this person.
|
|
283
|
+
outcomeQuality: 0.5,
|
|
268
284
|
surprise: 0.15,
|
|
269
|
-
lessons: [ `My
|
|
285
|
+
lessons: [ `My words are on their way to ${targetEntityName}. Whether they land is not yet known.` ],
|
|
270
286
|
},
|
|
271
287
|
}
|
|
272
288
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import type { EntityInput, Tick } from '#core/types'
|
|
19
19
|
import type { DenialFinality, PolicyCounterfactual } from '#stem/policy/arbiter'
|
|
20
|
+
import type { PlanLink } from '#agency/types'
|
|
20
21
|
|
|
21
22
|
export interface HostAckResult {
|
|
22
23
|
success: boolean
|
|
@@ -55,7 +56,7 @@ export interface HostAckResult {
|
|
|
55
56
|
* `agency.invocation` payload); `predictedReward`/`predictedValence` are the
|
|
56
57
|
* efference copy the executor persisted on the intent, so surprise is honest.
|
|
57
58
|
*
|
|
58
|
-
* `
|
|
59
|
+
* `planLink` carries the awaiting intent's plan step (planId/stepId) when it was
|
|
59
60
|
* committed from a plan's frontier prior. It rides on the agency.outcome so the
|
|
60
61
|
* ReafferenceEngine — the engine that consumes async-acked outcomes — can emit the
|
|
61
62
|
* `action.outcome{planId,stepId}` the PlanningEngine advances on. (The executor
|
|
@@ -68,7 +69,7 @@ export function reconcileInvocation(
|
|
|
68
69
|
result: HostAckResult,
|
|
69
70
|
tick: Tick,
|
|
70
71
|
predicted: { reward: number; valence: number } = { reward: 0.5, valence: 0 },
|
|
71
|
-
|
|
72
|
+
planLink: PlanLink = {},
|
|
72
73
|
): EntityInput {
|
|
73
74
|
const outcomeQuality = result.outcomeQuality ?? ( result.success ? 0.8 : 0.1 )
|
|
74
75
|
const valence = result.valence ?? ( result.success ? 0.2 : -0.2 )
|
|
@@ -94,8 +95,8 @@ export function reconcileInvocation(
|
|
|
94
95
|
// Only when the arbiter actually reported a bound — a refusal without one
|
|
95
96
|
// writes no key at all, so the quiet path is unchanged.
|
|
96
97
|
...( result.refused && result.counterfactual ? { counterfactual: result.counterfactual } : {} ),
|
|
97
|
-
...(
|
|
98
|
-
...(
|
|
98
|
+
...( planLink.planId ? { planId: planLink.planId } : {} ),
|
|
99
|
+
...( planLink.stepId ? { stepId: planLink.stepId } : {} ),
|
|
99
100
|
},
|
|
100
101
|
}
|
|
101
102
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/agency/restart.ts — the restart boundary
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// Two different things happen when a Will wakes from a snapshot, and conflating
|
|
6
|
+
// them is what made this a recurring class of bug rather than a single one:
|
|
7
|
+
//
|
|
8
|
+
// 1. TIME must not go backwards. Entities come back stamped with the tick they
|
|
9
|
+
// were written at, so the clock has to resume from the snapshot's tick
|
|
10
|
+
// rather than restart at 0 (WillStem.createWill does this via
|
|
11
|
+
// `clock.setTick`). Otherwise every `tick - stampedTick` in the codebase —
|
|
12
|
+
// 42 comparison sites across 19 files — computes a NEGATIVE age, and the
|
|
13
|
+
// guards built on them inverted spectacularly: an awaiting intent whose age
|
|
14
|
+
// read -589 could never time out, and the selector's staleness decay
|
|
15
|
+
// `1 - staleness × STALE_DECAY` became `1 + 19.6`, AMPLIFYING an incumbent
|
|
16
|
+
// from 0.47 to 9.74 and making it permanently unpreemptable.
|
|
17
|
+
//
|
|
18
|
+
// 2. Work that was IN FLIGHT does not resume. Resuming the clock fixes the
|
|
19
|
+
// arithmetic but says nothing about the semantics: an action dispatched
|
|
20
|
+
// moments before hibernation is not still dispatched hours later, and the
|
|
21
|
+
// window in which the world might have echoed our own words has closed.
|
|
22
|
+
// Leaving these behind is worse under a resumed clock than under a reset
|
|
23
|
+
// one, because they now look plausibly RECENT — an awaiting intent would be
|
|
24
|
+
// reconciled as a genuine timeout, teaching the mind that reaching that
|
|
25
|
+
// person does not work, when all that happened is that it slept.
|
|
26
|
+
//
|
|
27
|
+
// This module owns (2): what the agency considers in-flight, and therefore what
|
|
28
|
+
// must not cross the boundary. It is deliberately a short, explicit list rather
|
|
29
|
+
// than a heuristic — anything the agency stamps with a tick and expects to
|
|
30
|
+
// resolve within a few of them belongs here.
|
|
31
|
+
// ─────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
import { CONSEQUENCE_TYPE } from '#agency/consequence'
|
|
34
|
+
|
|
35
|
+
/** Entity type of a committed action awaiting the world's answer. */
|
|
36
|
+
const INTENT_TYPE = 'agency.intent'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Ids of the restored entities that represent work in flight when the mind went
|
|
40
|
+
* to sleep. Pure — the caller drops them.
|
|
41
|
+
*
|
|
42
|
+
* • `agency.intent` with status 'awaiting' — dispatched, never answered. It is
|
|
43
|
+
* ABANDONED, not failed: sleeping is not the world declining to answer, and
|
|
44
|
+
* recording a failure here would teach reafference a lesson about the process
|
|
45
|
+
* lifecycle rather than about the action.
|
|
46
|
+
* • `agency.consequence` — the expected sensory footprint of an act, used both
|
|
47
|
+
* to recognise our own echo (P2) and to damp repeating ourselves (P5). Its
|
|
48
|
+
* TTL is a handful of ticks; across a sleep the echo will never arrive, and a
|
|
49
|
+
* stale one both mis-attributes genuine replies as self-caused and suppresses
|
|
50
|
+
* contact that should now be free to happen.
|
|
51
|
+
*
|
|
52
|
+
* A `selected` intent is deliberately NOT cleared: it has not been dispatched, so
|
|
53
|
+
* it is still an intention the mind holds rather than an action in flight.
|
|
54
|
+
*/
|
|
55
|
+
export function inFlightOnRestore(
|
|
56
|
+
entities: ReadonlyMap<string, { type: string; metadata?: Record<string, unknown> }>,
|
|
57
|
+
): string[] {
|
|
58
|
+
const drop: string[] = []
|
|
59
|
+
|
|
60
|
+
for( const [ id, e ] of entities ){
|
|
61
|
+
if( e.type === CONSEQUENCE_TYPE ){ drop.push( id ); continue }
|
|
62
|
+
if( e.type === INTENT_TYPE && e.metadata?.['status'] === 'awaiting') drop.push( id )
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return drop
|
|
66
|
+
}
|
|
@@ -92,7 +92,102 @@ export const INNATE_SCHEMAS: MotorSchema[] = [
|
|
|
92
92
|
cost: 0.06,
|
|
93
93
|
preconditions: [ { metric: 'energy.level', op: 'gt', value: 8 } ],
|
|
94
94
|
baseValence: 0.05,
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Outward only — a question put to the world, which is the only thing that
|
|
97
|
+
* can answer it.
|
|
98
|
+
*
|
|
99
|
+
* Turning attention inward already has three names on this very floor:
|
|
100
|
+
* `orient` sweeps the situation, `attend` mobilises attention, `reflect`
|
|
101
|
+
* turns inward and lets patterns settle. `inspect` naming that too was a
|
|
102
|
+
* second name for an act that already had one.
|
|
103
|
+
*
|
|
104
|
+
* The collision was not stylistic. The two readings have DIFFERENT failure
|
|
105
|
+
* modes — "I hold no record of it" versus "the world did not answer" — so one
|
|
106
|
+
* verb covering both forced three disambiguation flags into a pure function,
|
|
107
|
+
* and left the inward reading unable to fail at all. Live, a fresh Will
|
|
108
|
+
* proceduralized this to habit 0.64 within fifteen ticks of birth and spent
|
|
109
|
+
* five of its first eight decisions on it, examining its own affordance
|
|
110
|
+
* entities and being told each time that it went well.
|
|
111
|
+
*
|
|
112
|
+
* Tagged external it rides the path `reach-out` already rides: dispatched to
|
|
113
|
+
* the host, held awaiting, acked or timed out. The ACK ITSELF carries the
|
|
114
|
+
* answer — `observation`, in whatever shape the host keeps it — and the
|
|
115
|
+
* engine turns that into a reafferent percept the mind judges for itself
|
|
116
|
+
* (SIGNAL_BOUNDARY P2). One act, one answer, one percept.
|
|
117
|
+
*
|
|
118
|
+
* This paragraph used to say the opposite: that an ack carried only
|
|
119
|
+
* `{success, description}` and so a host CANNOT hand facts back, which
|
|
120
|
+
* obliged every host to call `perceive()` a second time with its own result
|
|
121
|
+
* — the laundering that made a Will's own act arrive looking like news from
|
|
122
|
+
* the world. P2 removed the obligation; this comment outlived it by two
|
|
123
|
+
* merges, which is the ordinary way a false comment survives: nothing
|
|
124
|
+
* compiles it.
|
|
125
|
+
*
|
|
126
|
+
* A look nothing answers still fails, and that is what teaches a mind to
|
|
127
|
+
* stop examining what will not resolve. Through the SDK an effector with no
|
|
128
|
+
* handler is acked failed inside the tick; a host driving the stem directly
|
|
129
|
+
* leaves the intent awaiting until AWAIT_TIMEOUT abandons it.
|
|
130
|
+
*
|
|
131
|
+
* Innate AND host-dependent is not a contradiction; `reach-out` is both.
|
|
132
|
+
* Every mind can look, but whether looking finds anything depends on there
|
|
133
|
+
* being a world.
|
|
134
|
+
*/
|
|
135
|
+
tags: [ 'perception', 'information', 'external' ],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
/**
|
|
139
|
+
* Look at a clock.
|
|
140
|
+
*
|
|
141
|
+
* WHY THIS IS AN ACT AND NOT A FACT THE PROMPT HANDS OVER. A body knows its
|
|
142
|
+
* own rhythm — tired, alert, trough — because a rhythm is something a body
|
|
143
|
+
* DOES. It does not know that it is 15:42, because that is a fact about the
|
|
144
|
+
* world, and the only way a fact about the world reaches a mind is by the
|
|
145
|
+
* mind going and getting it. Every prompt used to carry the hour for free,
|
|
146
|
+
* and it was wrong in three ways at once precisely because nobody had to
|
|
147
|
+
* ask where it came from.
|
|
148
|
+
*
|
|
149
|
+
* Innate AND host-dependent, exactly as `inspect` and `reach-out` are:
|
|
150
|
+
* every mind can ask what time it is; whether anything answers depends on
|
|
151
|
+
* there being a world with a clock in it.
|
|
152
|
+
*
|
|
153
|
+
* A host that has one answers on the ack — `observation`, in whatever shape
|
|
154
|
+
* it keeps time: an ISO string, an hour and a zone, a mission-elapsed count.
|
|
155
|
+
* It does not have to phrase it, and it should not: the mind reads the data
|
|
156
|
+
* and makes the meaning of it (SIGNAL_BOUNDARY P2). The answer lands as a
|
|
157
|
+
* reafferent percept stamped with the intent that sought it, so what she
|
|
158
|
+
* knows about the hour is something she went and found, with a record of
|
|
159
|
+
* having found it.
|
|
160
|
+
*
|
|
161
|
+
* A host that has none never answers, and the failure is honest in either
|
|
162
|
+
* shape it takes: through the SDK an unregistered effector is acked failed
|
|
163
|
+
* inside the tick ("No handler registered for effector ..."), through the
|
|
164
|
+
* raw stem the intent sits awaiting until AWAIT_TIMEOUT abandons it. Either
|
|
165
|
+
* way the mind learns that time is not available here — which is a true
|
|
166
|
+
* thing about this world — rather than being handed a fiction.
|
|
167
|
+
*
|
|
168
|
+
* That degradation is the point of putting it here rather than in a config.
|
|
169
|
+
* A clock injected per-host is a fact one Will has and another does not,
|
|
170
|
+
* with no way for either to know which it is. Sought, it is the same
|
|
171
|
+
* mechanism for all of them, and the answer — or its absence — is
|
|
172
|
+
* something the mind can weigh.
|
|
173
|
+
*
|
|
174
|
+
* `binds: 'none'` because the time is not a referent. There is nothing to
|
|
175
|
+
* point at; you just look.
|
|
176
|
+
*/
|
|
177
|
+
id: 'check-time',
|
|
178
|
+
kind: 'primitive',
|
|
179
|
+
// 'innate', not 'perceptual'. `inspect` is perceptual because a percept
|
|
180
|
+
// EVOKES it — it binds the thing it looks at. Nothing evokes this; it is
|
|
181
|
+
// always there, like `orient` and `rest`. The synthesizer caps
|
|
182
|
+
// percept-evoked affordances at attention capacity and never caps the
|
|
183
|
+
// floor, and a glance at a clock belongs to the floor.
|
|
184
|
+
source: 'innate',
|
|
185
|
+
binds: 'none',
|
|
186
|
+
// Cheaper than `inspect` (0.06): a glance at a clock, not an examination.
|
|
187
|
+
cost: 0.03,
|
|
188
|
+
preconditions: [ { metric: 'energy.level', op: 'gt', value: 5 } ],
|
|
189
|
+
baseValence: 0.0,
|
|
190
|
+
tags: [ 'perception', 'information', 'external' ],
|
|
96
191
|
},
|
|
97
192
|
{
|
|
98
193
|
id: 'reach-out',
|
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
// paramPriors — last known-good parameters become defaults
|
|
25
25
|
// ─────────────────────────────────────────────────────────────
|
|
26
26
|
|
|
27
|
+
import { logger } from '#core/logger'
|
|
27
28
|
import type { MotorSchema, LearnedSkill } from '#agency/types'
|
|
28
29
|
import type { EntityInput, ReadonlySimulationState } from '#core/types'
|
|
29
30
|
import type { DenialFinality } from '#stem/policy/arbiter'
|
|
30
|
-
import { INNATE_SCHEMAS } from '#agency/schemas/innate'
|
|
31
|
+
import { INNATE_SCHEMAS, INNATE_SCHEMA_BY_ID } from '#agency/schemas/innate'
|
|
31
32
|
|
|
32
33
|
const VALUE_ALPHA = 0.2 // value EMA rate
|
|
33
34
|
const ERROR_BETA = 0.2 // prediction-error EMA rate
|
|
@@ -99,6 +100,23 @@ export class SchemaRepertoire {
|
|
|
99
100
|
* reafference then builds skill on. Idempotent; re-registering updates it.
|
|
100
101
|
*/
|
|
101
102
|
registerExternal( schema: MotorSchema ): void {
|
|
103
|
+
// An innate schema is part of the body, not a slot a tenant may redefine.
|
|
104
|
+
//
|
|
105
|
+
// This sets by id, so a host registering a handler for a name the floor
|
|
106
|
+
// already uses would REPLACE the innate schema with a generated one —
|
|
107
|
+
// silently dropping its `binds`, cost, preconditions and tags. `inspect` is
|
|
108
|
+
// the live case: a Discord bridge answering inquiries would have overwritten
|
|
109
|
+
// the very schema whose `binds: 'percept'` is how inquiry finds its targets,
|
|
110
|
+
// and the mind would have lost the ability to look at what it cannot place in
|
|
111
|
+
// exchange for gaining an answerer.
|
|
112
|
+
//
|
|
113
|
+
// Registering the HANDLER is still what the host wanted and still happens —
|
|
114
|
+
// only the redeclaration is refused. The container supplies the mechanism; a
|
|
115
|
+
// tenant supplies what answers it.
|
|
116
|
+
if( INNATE_SCHEMA_BY_ID.has( schema.id ) ){
|
|
117
|
+
logger.debug(`[repertoire] "${ schema.id }" is innate — keeping the body's schema, binding the handler only`)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
102
120
|
this._templates.set( schema.id, schema )
|
|
103
121
|
}
|
|
104
122
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
// + driveUrgency
|
|
14
14
|
// + habitStrength·W (additive habit bonus)
|
|
15
15
|
// + planBias·W (top-down prior)
|
|
16
|
+
// + willBias·W (deliberate volition)
|
|
17
|
+
// + socialPrior·W (learned read on WHO)
|
|
16
18
|
// − cost
|
|
17
19
|
// − inhibition
|
|
18
20
|
// − risk
|
|
@@ -47,9 +49,48 @@ export interface ScoreWeights {
|
|
|
47
49
|
habit: number
|
|
48
50
|
/** Top-down planning prior — how strongly an executing plan biases the competition. */
|
|
49
51
|
plan: number
|
|
52
|
+
/**
|
|
53
|
+
* Volitional prior — how strongly a DELIBERATE executive decision biases the
|
|
54
|
+
* competition. Peer of `plan`: a plan's frontier is a standing prior, a willed act
|
|
55
|
+
* is a prior formed this cycle. Strong enough that no habit (≤1) can out-weigh a
|
|
56
|
+
* confident decision, weak enough that inhibition, threat, or a genuinely more
|
|
57
|
+
* pressing affordance still can — willing is not a rubber stamp.
|
|
58
|
+
*/
|
|
59
|
+
will: number
|
|
60
|
+
/**
|
|
61
|
+
* How strongly the mind's LEARNED read on an addressee biases acting toward them.
|
|
62
|
+
* Peer of `goal` in magnitude: who someone has shown themselves to be should weigh
|
|
63
|
+
* about as much as a goal pointed at them. Signed — a person the mind has come to
|
|
64
|
+
* trust pulls it toward contact, one who never answers pulls it away — and it
|
|
65
|
+
* reaches zero for anyone unknown, so a mind that knows no one scores as before.
|
|
66
|
+
*/
|
|
67
|
+
social: number
|
|
50
68
|
cost: number
|
|
51
69
|
inhib: number
|
|
52
70
|
risk: number
|
|
71
|
+
/**
|
|
72
|
+
* How strongly an act's own live footprint damps doing it again (EXAFFERENCE
|
|
73
|
+
* P5). Satiation, not a lock: it decays with the descriptor, so the pull
|
|
74
|
+
* returns once the window in which the world could have answered has passed.
|
|
75
|
+
* Peer of `will` in magnitude — a freshly-delivered message should roughly
|
|
76
|
+
* cancel the volitional prior that produced it, and no more, so a genuinely
|
|
77
|
+
* pressing reason to speak again still wins.
|
|
78
|
+
*/
|
|
79
|
+
repeat: number
|
|
80
|
+
/**
|
|
81
|
+
* How strongly a verdict System 2 already reached holds the competition.
|
|
82
|
+
*
|
|
83
|
+
* Peer of `will` and `repeat` in magnitude, and for the same reason each of
|
|
84
|
+
* those is: having thought a choice through should weigh about what willing it
|
|
85
|
+
* does, and no more. Large enough that the settled option clears the
|
|
86
|
+
* selector's ambiguity gate (0.06) for most of the settlement's life, so the
|
|
87
|
+
* same question is not re-deliberated every few ticks; small enough that a
|
|
88
|
+
* genuinely pressing affordance — threat, a person waiting, a drive gone
|
|
89
|
+
* urgent — still out-competes a standing verdict.
|
|
90
|
+
*
|
|
91
|
+
* Decays to 0 with the settlement, so the question re-opens on its own.
|
|
92
|
+
*/
|
|
93
|
+
settled: number
|
|
53
94
|
}
|
|
54
95
|
|
|
55
96
|
export const DEFAULT_WEIGHTS: ScoreWeights = {
|
|
@@ -59,9 +100,13 @@ export const DEFAULT_WEIGHTS: ScoreWeights = {
|
|
|
59
100
|
drive: 0.25,
|
|
60
101
|
habit: 0.20,
|
|
61
102
|
plan: 0.30,
|
|
103
|
+
will: 0.30,
|
|
104
|
+
social: 0.30,
|
|
62
105
|
cost: 0.20,
|
|
63
106
|
inhib: 0.30,
|
|
64
107
|
risk: 0.20,
|
|
108
|
+
repeat: 0.30,
|
|
109
|
+
settled: 0.30,
|
|
65
110
|
}
|
|
66
111
|
|
|
67
112
|
/**
|
|
@@ -154,9 +199,13 @@ export function scoreAffordance(
|
|
|
154
199
|
+ w.drive * driveUrgency( a, bias )
|
|
155
200
|
+ w.habit * a.habitStrength
|
|
156
201
|
+ w.plan * ( a.planBias ?? 0 )
|
|
202
|
+
+ w.will * ( a.willBias ?? 0 )
|
|
203
|
+
+ w.social * ( a.socialPrior ?? 0 )
|
|
157
204
|
- w.cost * a.cost
|
|
158
205
|
- w.inhib * bias.inhibition
|
|
159
206
|
- w.risk * risk( a, bias )
|
|
207
|
+
- w.repeat * ( a.justEnacted ?? 0 )
|
|
208
|
+
+ w.settled * ( a.settled ?? 0 )
|
|
160
209
|
)
|
|
161
210
|
// POLICY_REAFFERENCE P2 — policy availability damps a POSITIVE activation only,
|
|
162
211
|
// never flipping its sign: a refused ability competes weakly (so it is rarely
|