@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
|
@@ -35,7 +35,12 @@ import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
|
35
35
|
import type { Affordance, AffordanceSource, MotorSchema, LearnedSkill, SchemaPrecondition } from '#agency/types'
|
|
36
36
|
import type { SchemaRepertoire } from '#agency/schemas/repertoire'
|
|
37
37
|
import { INNATE_SCHEMAS } from '#agency/schemas/innate'
|
|
38
|
+
import { CURIOUS_RESOLVED } from '#faculties/known.entity.tracker'
|
|
38
39
|
import { collectGoalTargets } from '#agency/selection.scoring'
|
|
40
|
+
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
41
|
+
import { liveConsequences, enactionFootprint, spokenAtByEntity, enactedAtBySchemaTarget, CONSEQUENCE_TTL_TICKS, type ConsequenceDescriptor } from '#agency/consequence'
|
|
42
|
+
import { readAliases, canonicalOf } from '#cognition/social.identity'
|
|
43
|
+
import { liveSettlements, settlementForce, type SettlementDescriptor } from '#agency/settlement'
|
|
39
44
|
|
|
40
45
|
/** Default field width for non-innate affordances when no attention metric exists. */
|
|
41
46
|
const DEFAULT_ATTENTION_CAP = 5
|
|
@@ -59,6 +64,38 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
59
64
|
private _schemas: MotorSchema[]
|
|
60
65
|
private _skills: SkillAccessor | null = null
|
|
61
66
|
private _repertoire: SchemaRepertoire | null = null
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* This tick's live consequence descriptors — the acts the mind has performed
|
|
70
|
+
* whose outcome has not yet come back. Refreshed once at the top of react()
|
|
71
|
+
* because `_build` runs per candidate and reading them is a full-entity scan.
|
|
72
|
+
*/
|
|
73
|
+
private _inFlight: readonly ConsequenceDescriptor[] = []
|
|
74
|
+
/** Durable "when did I last do this TO them" — the entity-bound peer of
|
|
75
|
+
* `_spokenAt`, collected once per tick for the same reason `_inFlight` is. */
|
|
76
|
+
private _enactedAt: ReadonlyMap<string, number> = new Map()
|
|
77
|
+
|
|
78
|
+
/** Ticks an act stays satiating (engine-config-action-selector.repeatWindowTicks). */
|
|
79
|
+
private _satiationWindow: number = CONSEQUENCE_TTL_TICKS
|
|
80
|
+
/** Verdicts System 2 has already reached and that have not yet aged out.
|
|
81
|
+
* Collected once per tick for the same reason `_inFlight` is — `_build` runs
|
|
82
|
+
* per candidate and this is a full-entity scan. */
|
|
83
|
+
private _settled: SettlementDescriptor[] = []
|
|
84
|
+
|
|
85
|
+
/** Tick of the last thing said to each entity — outlives the descriptor sweep. */
|
|
86
|
+
private _spokenAt: ReadonlyMap<string, number> = new Map()
|
|
87
|
+
private _spokeAnywhereAt: number | undefined = undefined
|
|
88
|
+
/**
|
|
89
|
+
* alias id → anchor id, read once per tick.
|
|
90
|
+
*
|
|
91
|
+
* Every surface below is keyed by WHO an act was aimed at, and the mind meets
|
|
92
|
+
* one person under more than one id: a reply is addressed to the transport id
|
|
93
|
+
* the percept arrived with (`discord:1019…`), a self-initiated message to the
|
|
94
|
+
* anchor the executive resolved (`ke:…`). `readSpokenTurns` resolved that for
|
|
95
|
+
* the PROMPT from the start; nothing resolved it for the WEIGHTS, so having
|
|
96
|
+
* just answered someone did not damp reaching out to them a cycle later.
|
|
97
|
+
*/
|
|
98
|
+
private _canon: ( id: string ) => string = id => id
|
|
62
99
|
private _bus: CognitiveBus | null = null
|
|
63
100
|
private _defaultCap: number
|
|
64
101
|
private _lastFieldSize = 0
|
|
@@ -112,6 +149,40 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
112
149
|
const valence = metric( state, 'affect.valence', 0 )
|
|
113
150
|
const energyLow = metric( state, 'energy.level', 0 ) < 30
|
|
114
151
|
|
|
152
|
+
// The mind's own acts still in flight (EXAFFERENCE P5). Read once per tick —
|
|
153
|
+
// `_build` runs for every candidate and this is a full-entity scan. Each
|
|
154
|
+
// candidate whose (schema, target) matches one of these carries a decaying
|
|
155
|
+
// `justEnacted`, so having just done a thing damps doing it again.
|
|
156
|
+
// One scan, then every target-keyed surface below shares its id space. They
|
|
157
|
+
// must agree with each other AND with the lookup at the call site: canonical
|
|
158
|
+
// keys read with a raw target damps nothing, and a raw key read with a
|
|
159
|
+
// canonical target breaks the damping that already worked.
|
|
160
|
+
const aliases = readAliases( state.entities )
|
|
161
|
+
this._canon = ( id: string ) => canonicalOf( aliases, id )
|
|
162
|
+
|
|
163
|
+
this._inFlight = liveConsequences( state.entities, tick, this._canon )
|
|
164
|
+
// Durable per-(schema, target) enaction. Descriptors alone expire at the ECHO
|
|
165
|
+
// window, so without this the back half of the satiation window damped
|
|
166
|
+
// nothing for any act with an object that is not speech.
|
|
167
|
+
this._enactedAt = enactedAtBySchemaTarget( state.entities, this._canon )
|
|
168
|
+
// What the mind has already decided. Read here so a verdict reaches the
|
|
169
|
+
// competition as a force in the field rather than a fact about one intent.
|
|
170
|
+
this._settled = liveSettlements( state.entities, tick, this._canon )
|
|
171
|
+
// How long this mind sits with something it has already done before doing it
|
|
172
|
+
// again — the tenant's, not the container's. Falls back to the echo TTL only
|
|
173
|
+
// when unseeded, so a bare harness behaves as before.
|
|
174
|
+
this._satiationWindow = readEffectiveParams( state, 'engine-config-action-selector').repeatWindowTicks
|
|
175
|
+
?? CONSEQUENCE_TTL_TICKS
|
|
176
|
+
// Durable "when did I last speak to them". Descriptors alone cannot carry
|
|
177
|
+
// satiation — the executor deletes them at their echo TTL, so any window
|
|
178
|
+
// longer than that was a no-op.
|
|
179
|
+
this._spokenAt = spokenAtByEntity( state.entities, this._canon )
|
|
180
|
+
// When this mind last spoke to ANYONE — the satiation arm that is not about
|
|
181
|
+
// the listener. Computed once per tick rather than per candidate.
|
|
182
|
+
let last = -Infinity
|
|
183
|
+
for( const t of this._spokenAt.values() ) if( t > last ) last = t
|
|
184
|
+
this._spokeAnywhereAt = last > -Infinity ? last : undefined
|
|
185
|
+
|
|
115
186
|
const set: EntityInput[] = []
|
|
116
187
|
const del: string[] = []
|
|
117
188
|
|
|
@@ -161,16 +232,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
161
232
|
const personSchemas = schemas.filter( s => s.binds === 'entity')
|
|
162
233
|
const objectSchemas = schemas.filter( s => s.binds === 'object')
|
|
163
234
|
|
|
164
|
-
|
|
165
|
-
|
|
235
|
+
// Not gated on there BEING a target-bound schema: `inspect` is offered from
|
|
236
|
+
// this same loop and belongs to the innate floor, so a mind with no `binds`
|
|
237
|
+
// schemas at all — which is every mind until a host declares one — must still
|
|
238
|
+
// reach it. Gating the loop skipped a room entirely, because the innate floor
|
|
239
|
+
// has no `binds: 'object'` schema for a thing to match.
|
|
240
|
+
for( const [ id, e ] of state.entities ){
|
|
166
241
|
if( e.type !== 'known-entity') continue
|
|
167
242
|
|
|
168
243
|
const m = e.metadata
|
|
169
244
|
const kind = str( m?.['kind'] )
|
|
170
245
|
const applicable = kind === 'sentient' ? personSchemas : kind === 'thing' ? objectSchemas : null
|
|
171
246
|
|
|
172
|
-
if( !applicable || applicable.length === 0 ) continue
|
|
173
|
-
|
|
174
247
|
const keid = str( m?.['keid'] ) ?? id
|
|
175
248
|
const fam = num( m?.['familiarity'], 0 )
|
|
176
249
|
const val = num( m?.['valence'], 0 )
|
|
@@ -178,7 +251,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
178
251
|
const salience = fam * 0.6 + Math.max( 0, val ) * 0.3 + res * 0.1 + ( goalTargets.get( keid ) ?? 0 )
|
|
179
252
|
const name = str( m?.['name'] ) ?? keid
|
|
180
253
|
|
|
181
|
-
for( const schema of applicable )
|
|
254
|
+
for( const schema of applicable ?? [] )
|
|
182
255
|
candidates.push({
|
|
183
256
|
salience,
|
|
184
257
|
affordance: this._build( schema, tick, state, valence, energyLow, skills, {
|
|
@@ -187,6 +260,38 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
187
260
|
parameters: { targetEntityName: name },
|
|
188
261
|
} ),
|
|
189
262
|
})
|
|
263
|
+
|
|
264
|
+
// ── looking at something I cannot place ──────────────────
|
|
265
|
+
//
|
|
266
|
+
// The wanting and the doing referenced different things. Curiosity is
|
|
267
|
+
// per-REFERENT — `drive.curiosity_resolve` rises with
|
|
268
|
+
// `familiarity × (1 − resolutionConfidence)`, and GoalManager turns it
|
|
269
|
+
// into a real goal that completes when that referent resolves. But the
|
|
270
|
+
// only `inspect` on offer bound to PERCEPTS, so a mind could want to know
|
|
271
|
+
// what a room was, hold a goal about it, and have no act that addressed
|
|
272
|
+
// it. The pull existed with nowhere to go.
|
|
273
|
+
//
|
|
274
|
+
// Offered here at the strength of the not-knowing itself, so the thing it
|
|
275
|
+
// most wants to place is the thing it is most drawn to look at — and the
|
|
276
|
+
// affordance appears BECAUSE something is unresolved rather than standing
|
|
277
|
+
// permanently on offer. A referent it can already place raises no
|
|
278
|
+
// candidate at all: there is nothing to find out.
|
|
279
|
+
//
|
|
280
|
+
// Alongside the percept-bound offering, not instead of it. Examining what
|
|
281
|
+
// is in front of you and looking up what you cannot place are both real,
|
|
282
|
+
// and they are not the same act.
|
|
283
|
+
if( perceptSchema && res < CURIOUS_RESOLVED ){
|
|
284
|
+
const wonder = fam * ( 1 - res )
|
|
285
|
+
if( wonder > 0 )
|
|
286
|
+
candidates.push({
|
|
287
|
+
salience: wonder + ( goalTargets.get( keid ) ?? 0 ),
|
|
288
|
+
affordance: this._build( perceptSchema, tick, state, valence, energyLow, skills, {
|
|
289
|
+
evokedBy: id,
|
|
290
|
+
targetEntityId: keid,
|
|
291
|
+
parameters: { focus: name, targetEntityName: name },
|
|
292
|
+
} ),
|
|
293
|
+
})
|
|
294
|
+
}
|
|
190
295
|
}
|
|
191
296
|
|
|
192
297
|
// ── ideomotor candidates: the executive's imagined actions, pre-activated ──
|
|
@@ -204,13 +309,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
204
309
|
|
|
205
310
|
if( !schema ) continue
|
|
206
311
|
|
|
312
|
+
// `priority` is the confidence the executive decided with. It sets BOTH the
|
|
313
|
+
// evoke-salience (field admission) and — via willBias — the activation the
|
|
314
|
+
// selector scores, so a decision made at 0.85 pushes harder than one at 0.5.
|
|
315
|
+
const willBias = clamp01( num( m?.['priority'], 0.8 ) )
|
|
207
316
|
candidates.push({
|
|
208
|
-
salience: IDEOMOTOR_BASE_SALIENCE +
|
|
317
|
+
salience: IDEOMOTOR_BASE_SALIENCE + willBias,
|
|
209
318
|
affordance: this._build( schema, tick, state, valence, energyLow, skills, {
|
|
210
319
|
evokedBy: id,
|
|
211
320
|
targetEntityId: str( m?.['targetEntityId'] ),
|
|
212
321
|
parameters: ( m?.['parameters'] as Record<string, unknown> ) ?? {},
|
|
213
322
|
source: 'ideomotor',
|
|
323
|
+
willBias,
|
|
214
324
|
} ),
|
|
215
325
|
})
|
|
216
326
|
}
|
|
@@ -220,7 +330,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
220
330
|
// action its current frontier needs. The PlanningEngine writes one `plan.prior`
|
|
221
331
|
// per ready frontier step; each enters the field as a HIGH-salience candidate
|
|
222
332
|
// (the frontier is willed) carrying a `planBias` the scorer weighs and the
|
|
223
|
-
// planId/stepId
|
|
333
|
+
// planId/stepId link that flows through to action.outcome so the plan
|
|
224
334
|
// advances when the field actually enacts it. Like ideomotor, it never bypasses
|
|
225
335
|
// the selector — if a more pressing affordance wins, the plan simply re-projects
|
|
226
336
|
// next tick. The suggested schema must resolve in the repertoire; if it does not,
|
|
@@ -303,6 +413,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
303
413
|
parameters?: Record<string, unknown>
|
|
304
414
|
source?: AffordanceSource
|
|
305
415
|
planBias?: number
|
|
416
|
+
willBias?: number
|
|
306
417
|
planId?: string
|
|
307
418
|
stepId?: string
|
|
308
419
|
},
|
|
@@ -313,6 +424,13 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
313
424
|
// Will's affordance field is byte-identical. Present only once a refusal dented it.
|
|
314
425
|
const availability = this._repertoire?.availabilityOf( schema.id ) ?? 1
|
|
315
426
|
|
|
427
|
+
// What the mind has LEARNED about the person this act is aimed at. Only for a
|
|
428
|
+
// targeted act; 0 for everything else, so the field is unchanged for a mind that
|
|
429
|
+
// knows no one. See Affordance.socialPrior.
|
|
430
|
+
const socialPrior = ctx.targetEntityId
|
|
431
|
+
? socialStanding( state, ctx.targetEntityId )
|
|
432
|
+
: 0
|
|
433
|
+
|
|
316
434
|
// Learned value if known, else the schema's intrinsic prior mapped to 0..1.
|
|
317
435
|
const expectedReward = skill?.valueEstimate ?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
|
|
318
436
|
const expectedValence = schema.baseValence ?? valence
|
|
@@ -320,6 +438,35 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
320
438
|
// Low energy makes everything feel costlier.
|
|
321
439
|
const cost = clamp01( schema.cost * ( energyLow ? 1.5 : 1 ) )
|
|
322
440
|
|
|
441
|
+
// This act's own footprint, if it is still in flight toward this same person.
|
|
442
|
+
// Satiation only applies to acts aimed at someone the mind SPEAKS to — the
|
|
443
|
+
// `conversation.sent` half is keyed by person, so it must not damp, say,
|
|
444
|
+
// inspecting them.
|
|
445
|
+
//
|
|
446
|
+
// For an act with NO OBJECT the footprint is the act itself: there is no
|
|
447
|
+
// target to key on, and "I have just done this" is the whole of the fact.
|
|
448
|
+
// The innate floor is entirely objectless, so without this it could not
|
|
449
|
+
// satiate at all and whichever stance won once won harder each tick after.
|
|
450
|
+
const speaks = schema.tags?.includes('communication') ?? false
|
|
451
|
+
// The lookup half. Only the QUESTION "have I just done this to them" is asked
|
|
452
|
+
// in canonical form — the affordance keeps the id it was built with, because
|
|
453
|
+
// that is the id the act will be delivered against.
|
|
454
|
+
const asked = ctx.targetEntityId ? this._canon( ctx.targetEntityId ) : undefined
|
|
455
|
+
const justEnacted = enactionFootprint(
|
|
456
|
+
this._inFlight, schema.id, asked, tick, this._satiationWindow,
|
|
457
|
+
speaks ? this._spokenAt : undefined,
|
|
458
|
+
skill?.lastEnactedTick,
|
|
459
|
+
speaks ? this._spokeAnywhereAt : undefined,
|
|
460
|
+
// Not gated on `speaks`: this is exactly the arm speech does NOT need
|
|
461
|
+
// (it has `spokenAt`) and every other entity-bound act was missing.
|
|
462
|
+
this._enactedAt,
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
// The mirror of satiation: having thought this through holds the choice for
|
|
466
|
+
// a while, and fades. Keyed exactly as `justEnacted` is, so an objectless
|
|
467
|
+
// verdict cannot leak onto an act that has an object.
|
|
468
|
+
const settled = settlementForce( this._settled, schema.id, asked, tick )
|
|
469
|
+
|
|
323
470
|
const key = ctx.targetEntityId ?? ctx.evokedBy ?? schema.id
|
|
324
471
|
const source = ctx.source ?? schema.source
|
|
325
472
|
// A non-default-source candidate (ideomotor) gets a distinct id so it can coexist
|
|
@@ -341,7 +488,11 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
341
488
|
tags: schema.tags ?? [],
|
|
342
489
|
...( schema.description ? { description: schema.description } : {} ),
|
|
343
490
|
...( availability < 1 ? { availability } : {} ),
|
|
491
|
+
...( socialPrior !== 0 ? { socialPrior } : {} ),
|
|
492
|
+
...( justEnacted > 0 ? { justEnacted } : {} ),
|
|
493
|
+
...( settled > 0 ? { settled } : {} ),
|
|
344
494
|
planBias: ctx.planBias,
|
|
495
|
+
willBias: ctx.willBias,
|
|
345
496
|
planId: ctx.planId,
|
|
346
497
|
stepId: ctx.stepId,
|
|
347
498
|
tick,
|
|
@@ -366,7 +517,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
|
|
|
366
517
|
tags: a.tags,
|
|
367
518
|
description: a.description,
|
|
368
519
|
...( a.availability !== undefined ? { availability: a.availability } : {} ),
|
|
520
|
+
...( a.socialPrior !== undefined ? { socialPrior: a.socialPrior } : {} ),
|
|
521
|
+
// The act's own footprint. Omitted when 0 so a mind that has done nothing
|
|
522
|
+
// twice writes a byte-identical field — but WRITTEN when it is not, which
|
|
523
|
+
// it never was: this is the state hop between synthesis and the
|
|
524
|
+
// competition, and `justEnacted` did not cross it.
|
|
525
|
+
...( a.justEnacted !== undefined ? { justEnacted: a.justEnacted } : {} ),
|
|
526
|
+
// The verdict's standing weight — same hop, same rule. A field the
|
|
527
|
+
// synthesizer computes and the entity does not carry is a field the
|
|
528
|
+
// competition never sees, which is how `justEnacted` stayed dormant.
|
|
529
|
+
...( a.settled !== undefined ? { settled: a.settled } : {} ),
|
|
369
530
|
planBias: a.planBias,
|
|
531
|
+
willBias: a.willBias,
|
|
370
532
|
planId: a.planId,
|
|
371
533
|
stepId: a.stepId,
|
|
372
534
|
tick: a.tick,
|
|
@@ -415,3 +577,34 @@ function str( v: unknown ): string | undefined {
|
|
|
415
577
|
function clamp01( n: number ): number {
|
|
416
578
|
return n < 0 ? 0 : n > 1 ? 1 : n
|
|
417
579
|
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* The mind's learned read on one person, −1..1 (0 = unknown or neutral).
|
|
583
|
+
*
|
|
584
|
+
* Every input is something the mind formed from experience, none is a constant:
|
|
585
|
+
* • ReputationTracker's `trustworthiness`, centred on 0.5 and scaled by that
|
|
586
|
+
* model's own `confidence`, so an opinion held on two interactions pushes
|
|
587
|
+
* far less than one held on fifty.
|
|
588
|
+
* • the mind's current affective tone, as a gentle tilt — feeling low makes
|
|
589
|
+
* reaching for anyone a little less attractive, which is a mood, not a verdict
|
|
590
|
+
* on them, so it is weighted small and applies the same way to everybody.
|
|
591
|
+
*
|
|
592
|
+
* This is the path by which "they never answer me" reaches the competition: the
|
|
593
|
+
* ReputationTracker learns it from `interaction.occurred`, which only started firing
|
|
594
|
+
* once inbound conversation reached social cognition (#113).
|
|
595
|
+
*/
|
|
596
|
+
function socialStanding( state: ReadonlySimulationState, keid: string ): number {
|
|
597
|
+
let trust = 0
|
|
598
|
+
for( const e of state.entities.values() ){
|
|
599
|
+
if( e.type !== 'reputation') continue
|
|
600
|
+
const m = e.metadata as Record<string, unknown> | undefined
|
|
601
|
+
if( m?.['keid'] !== keid ) continue
|
|
602
|
+
const t = num( m['trustworthiness'], 0.5 )
|
|
603
|
+
const c = clamp01( num( m['confidence'], 0 ) )
|
|
604
|
+
trust = ( t - 0.5 ) * 2 * c
|
|
605
|
+
break
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const mood = num( state.metrics.get('affect.valence'), 0 ) * 0.25
|
|
609
|
+
return Math.max( -1, Math.min( 1, trust + mood ) )
|
|
610
|
+
}
|
|
@@ -31,6 +31,8 @@ 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
33
|
import { revokedIntentIds, revocationId } from '#agency/revocation'
|
|
34
|
+
import { settlementEntity, expiredSettlementIds, SETTLEMENT_TTL_TICKS } from '#agency/settlement'
|
|
35
|
+
import { nameOf, isReferentId } from '#cognition/social.identity'
|
|
34
36
|
|
|
35
37
|
// ── Minimal structural view of the executive's facet machinery ───────────────
|
|
36
38
|
// Kept structural (not an import of the executive engine) so the agency module
|
|
@@ -98,7 +100,10 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
98
100
|
// to let go of it — and the tombstone with it. We never deliberate a
|
|
99
101
|
// revoked intent.
|
|
100
102
|
const revoked = revokedIntentIds( state.entities, tick )
|
|
101
|
-
|
|
103
|
+
// Aged-out verdicts go with them. Nothing else owns settlements, and a
|
|
104
|
+
// question whose settlement has expired must be genuinely open again — not
|
|
105
|
+
// merely inert-but-present, which would leave the state growing forever.
|
|
106
|
+
const del: string[] = expiredSettlementIds( state.entities, tick )
|
|
102
107
|
|
|
103
108
|
// One deliberation per tick (the serial bottleneck).
|
|
104
109
|
let target: { id: string; meta: Record<string, unknown> } | null = null
|
|
@@ -136,7 +141,15 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
136
141
|
|
|
137
142
|
return {
|
|
138
143
|
commands: {
|
|
139
|
-
set:
|
|
144
|
+
set: [
|
|
145
|
+
this._commit( id, meta, chosen, candidates, 'facet'),
|
|
146
|
+
// The verdict's trace in the field it was called in to resolve.
|
|
147
|
+
// Written ONLY here, on the path where System 2 actually thought —
|
|
148
|
+
// the no-executive path below confirms the substrate's winner without
|
|
149
|
+
// reaching a conclusion, and a mind should not be held to a verdict it
|
|
150
|
+
// never formed.
|
|
151
|
+
this._settle( chosen, candidates, tick ),
|
|
152
|
+
],
|
|
140
153
|
...( del.length > 0 ? { delete: del } : {} ),
|
|
141
154
|
metrics: [ [ 'agency.deliberation.count', 1 ] ],
|
|
142
155
|
},
|
|
@@ -186,6 +199,25 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
186
199
|
}
|
|
187
200
|
}
|
|
188
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Record that this contest was weighed and settled.
|
|
204
|
+
*
|
|
205
|
+
* Keyed on what WON, not on the rival set, so a slightly differently-framed
|
|
206
|
+
* contest still meets a verdict the mind has already reached — the rivals ride
|
|
207
|
+
* along as the introspectable reason rather than as a matching key.
|
|
208
|
+
*/
|
|
209
|
+
private _settle( chosen: string, candidates: Candidate[], tick: Tick ): EntityInput {
|
|
210
|
+
const cand = candidates.find( c => c.schema === chosen )
|
|
211
|
+
const over = candidates.filter( c => c.schema !== chosen ).map( c => c.schema )
|
|
212
|
+
return settlementEntity({
|
|
213
|
+
schema: chosen,
|
|
214
|
+
targetEntityId: cand?.targetEntityId,
|
|
215
|
+
...( over.length > 0 ? { over } : {} ),
|
|
216
|
+
tick,
|
|
217
|
+
expiresAt: tick + SETTLEMENT_TTL_TICKS,
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
|
|
189
221
|
/** Write the deliberating intent back as 'selected' with the chosen action. */
|
|
190
222
|
private _commit(
|
|
191
223
|
id: string,
|
|
@@ -227,7 +259,35 @@ export class DeliberationEngine implements CognitiveEngine {
|
|
|
227
259
|
else
|
|
228
260
|
lines.push('My automatic action-selection was uncertain. Candidate actions:')
|
|
229
261
|
candidates.forEach( ( c, i ) => {
|
|
230
|
-
|
|
262
|
+
// What the target IS, never the id it is filed under.
|
|
263
|
+
//
|
|
264
|
+
// This printed `c.targetEntityId` raw, so a mind deliberating was offered
|
|
265
|
+
// "inspect toward agency-intent-30" and "inspect toward
|
|
266
|
+
// affordance-1-orient-orient" — engine bookkeeping ids, and by the time a
|
|
267
|
+
// facet reasons off-tick the affordance entities are already swept. Live,
|
|
268
|
+
// she said so herself: "the content of all three is opaque — I don't know
|
|
269
|
+
// what agency-intent-30 actually is", and chose at 0.3 confidence anyway
|
|
270
|
+
// because the instructions forbid inventing an action outside the list.
|
|
271
|
+
//
|
|
272
|
+
// The prompt factory already holds this line for "## People I Know"
|
|
273
|
+
// ("never leak the raw keid"); the deliberation focus is the one place that
|
|
274
|
+
// did not. Resolved through the same dossier lookup, so a `reach-out toward
|
|
275
|
+
// ke:1sqlkux` now reads as the person's name.
|
|
276
|
+
//
|
|
277
|
+
// Unresolvable ⇒ the clause is DROPPED rather than filled with an id. An
|
|
278
|
+
// option the mind cannot identify should look like what it is — a bare act
|
|
279
|
+
// — instead of borrowing authority from a number it cannot read.
|
|
280
|
+
const to = ( () => {
|
|
281
|
+
const id = c.targetEntityId
|
|
282
|
+
if( !id ) return ''
|
|
283
|
+
const named = nameOf( state.entities as never, id )
|
|
284
|
+
if( named ) return ` toward ${ named }`
|
|
285
|
+
// Unnamed: show it only if it means something to the MIND. A host-supplied
|
|
286
|
+
// target ("ada") does; an opaque anchor or a piece of engine bookkeeping
|
|
287
|
+
// does not, and printing those is what produced "inspect toward
|
|
288
|
+
// agency-intent-30" as a thing to choose.
|
|
289
|
+
return opaqueToTheMind( id ) ? '' : ` toward ${ id }`
|
|
290
|
+
} )()
|
|
231
291
|
// The ability's meaning, so the facet weighs what each option IS FOR rather
|
|
232
292
|
// than choosing among bare labels ("give" vs "attack" is a real difference).
|
|
233
293
|
const what = c.description ? ` — ${ c.description }` : ''
|
|
@@ -258,3 +318,16 @@ function extractChosen( decision: unknown, candidates: Candidate[] ): string | u
|
|
|
258
318
|
function str( v: unknown ): string | undefined {
|
|
259
319
|
return typeof v === 'string' ? v : undefined
|
|
260
320
|
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Ids the mind cannot read anything off.
|
|
324
|
+
*
|
|
325
|
+
* A `ke:` anchor is opaque BY DESIGN — 0.9.0 made identity deliberately
|
|
326
|
+
* meaningless as a string — and the rest are the engine's own bookkeeping
|
|
327
|
+
* entities, which exist for one tick and say nothing about the world. Neither
|
|
328
|
+
* belongs in a choice a mind has to make; a host-supplied target does.
|
|
329
|
+
*/
|
|
330
|
+
function opaqueToTheMind( id: string ): boolean {
|
|
331
|
+
return isReferentId( id )
|
|
332
|
+
|| /^(affordance|agency-intent|agency-outcome|ideomotor|facet|percept)[-:]/.test( id )
|
|
333
|
+
}
|