@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
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/agency/settlement.ts — having thought about it
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// The agency has always been able to represent having ACTED. It could not
|
|
6
|
+
// represent having DECIDED.
|
|
7
|
+
//
|
|
8
|
+
// System 2 is recruited when the field is ambiguous — `margin < marginGate` in
|
|
9
|
+
// the ActionSelector, where margin is the activation gap between the top two
|
|
10
|
+
// affordances. The DeliberationEngine then resolves the contest and writes back
|
|
11
|
+
// exactly one thing: that intent flipped to 'selected', carrying `deliberated:
|
|
12
|
+
// true`. Nothing reads `deliberated`. The synthesizer rebuilds the field from
|
|
13
|
+
// scratch next tick, the same rivals score the same, the margin is again below
|
|
14
|
+
// the gate, and the same question is deliberated again.
|
|
15
|
+
//
|
|
16
|
+
// Measured on a live COO over 7 hours: 149 deliberations, median gap between
|
|
17
|
+
// them 17 seconds, 139 of 148 gaps under a minute — one LLM call every ~3 ticks
|
|
18
|
+
// for the whole run, and the single largest line in her cost. She could see it
|
|
19
|
+
// and had no mechanism to leave it:
|
|
20
|
+
//
|
|
21
|
+
// "Nothing has changed since my last ten deliberation cycles. Goal-7 is
|
|
22
|
+
// externally blocked — this is a fact, not a diagnosis I need to reach again."
|
|
23
|
+
// "I have composed the same message to FKEM across twelve deliberation cycles
|
|
24
|
+
// and not sent it."
|
|
25
|
+
// "There is nothing left to deliberate. I am looking."
|
|
26
|
+
//
|
|
27
|
+
// So: a settlement is the trace a verdict leaves in the field it was called in
|
|
28
|
+
// to resolve. It is the missing peer of a family the engine already has —
|
|
29
|
+
// having acted damps re-acting (`justEnacted`), having spoken damps re-speaking
|
|
30
|
+
// (`spokeAnywhereAt`), having committed can be withdrawn (revocation
|
|
31
|
+
// tombstones) — and having thought damped nothing at all.
|
|
32
|
+
//
|
|
33
|
+
// The mechanism is deliberately ONE quantity doing both jobs. Raising the
|
|
34
|
+
// settled option's activation means (a) the verdict has force, so System 1 does
|
|
35
|
+
// not coin-flip its way to a different answer on the next tick of the same flat
|
|
36
|
+
// field, and (b) the margin to the runner-up widens past the gate, so System 2
|
|
37
|
+
// is not recruited for a question it has already answered. The flatness is what
|
|
38
|
+
// summoned deliberation; the verdict is what gives the field the shape it
|
|
39
|
+
// lacked.
|
|
40
|
+
//
|
|
41
|
+
// And it DECAYS, like everything else here. This is a refractory period, not a
|
|
42
|
+
// lock — the user's objection to "a hard conditional gate that does not promise
|
|
43
|
+
// any flexibility or dynamism of the mind" is the whole design constraint. As
|
|
44
|
+
// the settlement ages the field flattens again and the question genuinely
|
|
45
|
+
// re-opens; a rupture revokes it outright through the machinery that already
|
|
46
|
+
// exists. A mind may always change its mind. It should not have to reach the
|
|
47
|
+
// same conclusion every three seconds to keep holding it.
|
|
48
|
+
// ─────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
import type { EntityInput, Tick } from '#core/types'
|
|
51
|
+
|
|
52
|
+
export const SETTLEMENT_TYPE = 'agency.settlement'
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Ticks a verdict holds before the question is genuinely open again.
|
|
56
|
+
*
|
|
57
|
+
* Set to the satiation window rather than the echo window, and the symmetry is
|
|
58
|
+
* the argument: having thought about something should hold about as long as
|
|
59
|
+
* having done it. The echo window (`CONSEQUENCE_TTL_TICKS`, 30) answers "could
|
|
60
|
+
* the world still be replying to me" — a different and necessarily shorter
|
|
61
|
+
* question that has nothing to do with whether a choice is settled.
|
|
62
|
+
*
|
|
63
|
+
* At the COO's observed rate (~5s/tick) this is roughly five minutes of held
|
|
64
|
+
* verdict, against a mind that was re-deciding every three ticks.
|
|
65
|
+
*/
|
|
66
|
+
export const SETTLEMENT_TTL_TICKS = 60
|
|
67
|
+
|
|
68
|
+
export interface SettlementDescriptor {
|
|
69
|
+
/** The act that won the contest. */
|
|
70
|
+
schema: string
|
|
71
|
+
/** Its object, when it has one — keyed exactly as satiation is, on purpose. */
|
|
72
|
+
targetEntityId?: string
|
|
73
|
+
/**
|
|
74
|
+
* The rivals it was weighed against.
|
|
75
|
+
*
|
|
76
|
+
* Not used for matching — a settlement is keyed on what WON, so a slightly
|
|
77
|
+
* differently-framed contest still meets a verdict the mind has already
|
|
78
|
+
* reached. Carried because "I decided this over that" is the introspectable
|
|
79
|
+
* fact, and a settlement with no memory of what it beat is a preference with
|
|
80
|
+
* no reason attached.
|
|
81
|
+
*/
|
|
82
|
+
over?: readonly string[]
|
|
83
|
+
tick: Tick
|
|
84
|
+
expiresAt: Tick
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Stable id — one settlement per (schema, target), so re-deciding refreshes it. */
|
|
88
|
+
export function settlementId( schema: string, targetEntityId?: string ): string {
|
|
89
|
+
return `agency-settlement-${ schema }${ targetEntityId ? `-${ targetEntityId }` : '' }`
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Build the settlement entity. Ordinary state, so it snapshots and replays (FN9). */
|
|
93
|
+
export function settlementEntity( d: SettlementDescriptor ): EntityInput {
|
|
94
|
+
return {
|
|
95
|
+
id: settlementId( d.schema, d.targetEntityId ),
|
|
96
|
+
type: SETTLEMENT_TYPE,
|
|
97
|
+
metadata: { ...d, ...( d.over ? { over: [ ...d.over ] } : {} ) },
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Read a settlement back off entity metadata.
|
|
103
|
+
*
|
|
104
|
+
* Decoded field-for-field, including `over`. A value written by one side and
|
|
105
|
+
* never read by the other is the defect shape this codebase has now hit six
|
|
106
|
+
* times, and it is the exact defect this module exists to fix — `deliberated:
|
|
107
|
+
* true` was written on every deliberated intent and read by nobody.
|
|
108
|
+
*/
|
|
109
|
+
export function readSettlement(
|
|
110
|
+
m: ReadonlyMap<string, unknown> | Record<string, unknown> | undefined,
|
|
111
|
+
): SettlementDescriptor | null {
|
|
112
|
+
const meta = ( m instanceof Map ? Object.fromEntries( m ) : m ?? {} ) as Record<string, unknown>
|
|
113
|
+
const schema = typeof meta['schema'] === 'string' ? meta['schema'] as string : undefined
|
|
114
|
+
if( !schema ) return null
|
|
115
|
+
|
|
116
|
+
const over = Array.isArray( meta['over'] )
|
|
117
|
+
? ( meta['over'] as unknown[] ).filter( ( x ): x is string => typeof x === 'string' )
|
|
118
|
+
: undefined
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
schema,
|
|
122
|
+
targetEntityId: typeof meta['targetEntityId'] === 'string' ? meta['targetEntityId'] as string : undefined,
|
|
123
|
+
...( over && over.length > 0 ? { over } : {} ),
|
|
124
|
+
tick: typeof meta['tick'] === 'number' ? meta['tick'] as number : 0,
|
|
125
|
+
expiresAt: typeof meta['expiresAt'] === 'number' ? meta['expiresAt'] as number : 0,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The live (unexpired) settlements in frozen state, in stable id order. */
|
|
130
|
+
export function liveSettlements(
|
|
131
|
+
entities: ReadonlyMap<string, { type: string; metadata?: ReadonlyMap<string, unknown> | Record<string, unknown> }>,
|
|
132
|
+
tick: Tick,
|
|
133
|
+
/**
|
|
134
|
+
* alias id → anchor id. Settlement is keyed exactly as satiation is — see the
|
|
135
|
+
* note on `settlementForce` — so it has to share satiation's id space too, or a
|
|
136
|
+
* verdict reached about a person under one id would not hold about them under
|
|
137
|
+
* the other. A function, not the table: see `liveConsequences`.
|
|
138
|
+
*/
|
|
139
|
+
canon?: ( id: string ) => string,
|
|
140
|
+
): SettlementDescriptor[] {
|
|
141
|
+
const out: Array<{ id: string; d: SettlementDescriptor }> = []
|
|
142
|
+
|
|
143
|
+
for( const [ id, e ] of entities ){
|
|
144
|
+
if( e.type !== SETTLEMENT_TYPE ) continue
|
|
145
|
+
const d = readSettlement( e.metadata )
|
|
146
|
+
if( !d ) continue
|
|
147
|
+
// Stamped LATER than now ⇒ restored from a previous session, where the tick
|
|
148
|
+
// counter restarts at 1 on wake. Without this a woken mind reads every
|
|
149
|
+
// settlement it ever made as freshly decided and cannot deliberate at all.
|
|
150
|
+
// The same trap `liveConsequences` documents, and the same fix.
|
|
151
|
+
if( d.tick > tick ) continue
|
|
152
|
+
if( tick < d.expiresAt )
|
|
153
|
+
out.push({ id, d: canon && d.targetEntityId
|
|
154
|
+
? { ...d, targetEntityId: canon( d.targetEntityId ) }
|
|
155
|
+
: d })
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return out.sort( ( a, b ) => ( a.id < b.id ? -1 : a.id > b.id ? 1 : 0 ) ).map( x => x.d )
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Settlement ids that have aged out — swept by the DeliberationEngine. */
|
|
162
|
+
export function expiredSettlementIds(
|
|
163
|
+
entities: ReadonlyMap<string, { type: string; metadata?: ReadonlyMap<string, unknown> | Record<string, unknown> }>,
|
|
164
|
+
tick: Tick,
|
|
165
|
+
): string[] {
|
|
166
|
+
const out: string[] = []
|
|
167
|
+
for( const [ id, e ] of entities ){
|
|
168
|
+
if( e.type !== SETTLEMENT_TYPE ) continue
|
|
169
|
+
const d = readSettlement( e.metadata )
|
|
170
|
+
if( d && tick >= d.expiresAt ) out.push( id )
|
|
171
|
+
}
|
|
172
|
+
return out
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* How much of a verdict on this (schema, target) is still standing, 1 → 0.
|
|
177
|
+
*
|
|
178
|
+
* Linear decay over the window, matching `enactionFootprint` — the two are
|
|
179
|
+
* mirror images and should feel the same from inside: one is the fading pull
|
|
180
|
+
* not to repeat an act, this is the fading weight of having already chosen.
|
|
181
|
+
*
|
|
182
|
+
* An objectless act matches an objectless settlement only. Deciding to `rest`
|
|
183
|
+
* says nothing about whether to `reach-out` to Ada, and a verdict that leaked
|
|
184
|
+
* across objects would be a mind that mistakes one question for another.
|
|
185
|
+
*/
|
|
186
|
+
export function settlementForce(
|
|
187
|
+
settlements: readonly SettlementDescriptor[],
|
|
188
|
+
schema: string,
|
|
189
|
+
targetEntityId: string | undefined,
|
|
190
|
+
tick: Tick,
|
|
191
|
+
windowTicks: number = SETTLEMENT_TTL_TICKS,
|
|
192
|
+
): number {
|
|
193
|
+
if( windowTicks <= 0 ) return 0
|
|
194
|
+
|
|
195
|
+
let strongest = 0
|
|
196
|
+
for( const s of settlements ){
|
|
197
|
+
if( s.schema !== schema || s.targetEntityId !== targetEntityId ) continue
|
|
198
|
+
const remaining = ( windowTicks - ( tick - s.tick ) ) / windowTicks
|
|
199
|
+
if( remaining > strongest ) strongest = remaining
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return strongest < 0 ? 0 : strongest > 1 ? 1 : strongest
|
|
203
|
+
}
|
|
@@ -118,7 +118,7 @@ export interface Affordance {
|
|
|
118
118
|
parameters: Record<string, unknown>
|
|
119
119
|
/** Bound target entity id, when the schema binds an entity. */
|
|
120
120
|
targetEntityId?: string
|
|
121
|
-
/** Entity id of the percept / known-entity that evoked this
|
|
121
|
+
/** Entity id of the percept / known-entity that evoked this. */
|
|
122
122
|
evokedBy?: string
|
|
123
123
|
/** Anticipated affective outcome −1..1 (learned, falling back to schema prior). */
|
|
124
124
|
expectedValence: number
|
|
@@ -140,6 +140,29 @@ export interface Affordance {
|
|
|
140
140
|
* competition WITHOUT bypassing it (the plan biases; the field still decides).
|
|
141
141
|
*/
|
|
142
142
|
planBias?: number
|
|
143
|
+
/**
|
|
144
|
+
* Top-down volitional bias 0..1 — set when the executive DELIBERATELY willed this
|
|
145
|
+
* affordance (source 'ideomotor'), carrying the confidence it decided with. Like
|
|
146
|
+
* planBias it lifts activation without bypassing the competition: a willed act must
|
|
147
|
+
* still out-compete the field, but it no longer arrives with the same standing as an
|
|
148
|
+
* ambient possibility. Without this term the ideomotor leg created candidates the
|
|
149
|
+
* arithmetic could not tell apart from idle ones, and a cheap unconditional reflex
|
|
150
|
+
* ('express', cost 0.02) beat a deliberate 'reach-out' 176 times out of 176.
|
|
151
|
+
*/
|
|
152
|
+
willBias?: number
|
|
153
|
+
/**
|
|
154
|
+
* Learned social standing of this affordance's addressee, −1..1 (0 = neutral or
|
|
155
|
+
* unknown). Set only for an act aimed at someone. Every input is LEARNED, none
|
|
156
|
+
* hardcoded: ReputationTracker's trustworthiness — which is fed by
|
|
157
|
+
* `interaction.occurred` and so only became live once inbound conversation reached
|
|
158
|
+
* social cognition (#113) — weighted by that model's own confidence, plus the mind's
|
|
159
|
+
* current affective tone as a gentle tilt on reaching out at all.
|
|
160
|
+
*
|
|
161
|
+
* This is what makes "they never answer me" reach the competition: it arrives as a
|
|
162
|
+
* fading opinion of a person the mind formed itself and can revise, not as a damping
|
|
163
|
+
* curve applied behind its back.
|
|
164
|
+
*/
|
|
165
|
+
socialPrior?: number
|
|
143
166
|
/**
|
|
144
167
|
* Policy availability 0..1 (POLICY_REAFFERENCE P2) — learned from refusals,
|
|
145
168
|
* distinct from `available` (precondition satisfaction) and from competence.
|
|
@@ -149,6 +172,38 @@ export interface Affordance {
|
|
|
149
172
|
* gets an occasional re-probe and can climb back as availability recovers.
|
|
150
173
|
*/
|
|
151
174
|
availability?: number
|
|
175
|
+
/**
|
|
176
|
+
* How much of this act's OWN footprint is still live, 1 → 0 (EXAFFERENCE P5).
|
|
177
|
+
* Set when a consequence descriptor for the same (schema, target) has not yet
|
|
178
|
+
* expired — the mind has just done this and does not yet know how it landed.
|
|
179
|
+
*
|
|
180
|
+
* Damps the pull to do it again, and decays back to 0 on its own, so a silence
|
|
181
|
+
* that starts to matter can still out-compete it. Without this the executive's
|
|
182
|
+
* standing `ideomotor.intent` outlived the act it produced: the same two
|
|
183
|
+
* messages were delivered to the same person three times, ~21 ticks apart,
|
|
184
|
+
* each time as though it were the first.
|
|
185
|
+
*/
|
|
186
|
+
justEnacted?: number
|
|
187
|
+
/**
|
|
188
|
+
* How much of a DELIBERATED verdict on this act is still standing, 1 → 0.
|
|
189
|
+
*
|
|
190
|
+
* The mirror of `justEnacted`: that one is the fading pull not to repeat
|
|
191
|
+
* something done, this is the fading weight of having already chosen. Set
|
|
192
|
+
* when System 2 resolved a contest in this act's favour and the settlement
|
|
193
|
+
* has not yet aged out.
|
|
194
|
+
*
|
|
195
|
+
* It does two things with one quantity, which is why it is a quantity and not
|
|
196
|
+
* a flag. The verdict gets force, so System 1 does not coin-flip its way to a
|
|
197
|
+
* different answer on the next tick of the same flat field; and the margin to
|
|
198
|
+
* the runner-up widens past the selector's gate, so System 2 is not recruited
|
|
199
|
+
* for a question it has already answered. Flatness is what summons
|
|
200
|
+
* deliberation — the verdict is what gives the field the shape it lacked.
|
|
201
|
+
*
|
|
202
|
+
* Without it, a live COO deliberated 149 times in 7 hours, median 17s apart,
|
|
203
|
+
* re-reaching the same conclusion about an externally-blocked goal until she
|
|
204
|
+
* wrote "this is a fact, not a diagnosis I need to reach again".
|
|
205
|
+
*/
|
|
206
|
+
settled?: number
|
|
152
207
|
/** Provenance: the plan whose frontier step projected this affordance. */
|
|
153
208
|
planId?: string
|
|
154
209
|
/** Provenance: the frontier step id — flows through to action.outcome so the plan advances. */
|
|
@@ -156,6 +211,23 @@ export interface Affordance {
|
|
|
156
211
|
tick: number
|
|
157
212
|
}
|
|
158
213
|
|
|
214
|
+
/**
|
|
215
|
+
* PlanLink — where an act sits in a plan: the frontier step it serves, if any.
|
|
216
|
+
* Rides on the `agency.outcome` so the PlanningEngine can advance the step the
|
|
217
|
+
* act was committed from.
|
|
218
|
+
*
|
|
219
|
+
* NAMED, AND NAMED THIS, BECAUSE IT USED TO BE CALLED `provenance`
|
|
220
|
+
* (SIGNAL_BOUNDARY P3). Two unrelated concepts shared that word in one codebase:
|
|
221
|
+
* this one, and `SignalProvenance` — whether a signal came from the world or
|
|
222
|
+
* from the mind's own act. The signal sense is the one the vocabulary needs, so
|
|
223
|
+
* this one gives the word up. An inline `{ planId?, stepId? }` in three
|
|
224
|
+
* signatures is also how the collision stayed invisible; a name can be grepped.
|
|
225
|
+
*/
|
|
226
|
+
export interface PlanLink {
|
|
227
|
+
planId?: string
|
|
228
|
+
stepId?: string
|
|
229
|
+
}
|
|
230
|
+
|
|
159
231
|
/**
|
|
160
232
|
* EfferenceCopy — the forward model's prediction of an action's own consequences,
|
|
161
233
|
* emitted *before* enaction so reafference has something to compare against.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/cache/composition.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compositional operators for cache interpolation.
|
|
7
|
+
*
|
|
8
|
+
* Design principle (from the research sketch): interpolate what is safe to
|
|
9
|
+
* interpolate, copy verbatim what is not. Executive actions carry free-text
|
|
10
|
+
* fields (`reasoning`, `expectedOutcome`) that would turn to gibberish under
|
|
11
|
+
* blending, so the ACTIONS block uses a weighted *vote* over action type and
|
|
12
|
+
* then copies the winning neighbor's action objects verbatim. Numeric scalars
|
|
13
|
+
* (goal priority, belief confidence) are the only fields we mean-blend.
|
|
14
|
+
*
|
|
15
|
+
* Every operator is deterministic: inputs arrive pre-sorted from the cache and
|
|
16
|
+
* ties are resolved by neighbor order (already deterministic), never by hashing.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { ExecutiveOutputFull } from '#faculties/executive.engine/types'
|
|
20
|
+
import type { ScoredNeighbor, CacheScope } from './types'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compose a valid ExecutiveOutputFull from scored neighbors. `neighbors` must be
|
|
24
|
+
* non-empty and ordered best-first (as the cache returns them). The three
|
|
25
|
+
* required fields (actions, reasoning, confidence) are always populated.
|
|
26
|
+
*/
|
|
27
|
+
export function composeOutput(
|
|
28
|
+
neighbors: ScoredNeighbor[],
|
|
29
|
+
tau: number,
|
|
30
|
+
scopes: CacheScope[],
|
|
31
|
+
): ExecutiveOutputFull {
|
|
32
|
+
const weights = _softmaxWeights( neighbors, tau )
|
|
33
|
+
|
|
34
|
+
// The best neighbor anchors required fields when a scope leaves them empty.
|
|
35
|
+
const anchor = neighbors[ 0 ]!.pattern.output
|
|
36
|
+
|
|
37
|
+
const out: ExecutiveOutputFull = {
|
|
38
|
+
actions: [],
|
|
39
|
+
reasoning: anchor.reasoning ?? '',
|
|
40
|
+
confidence: anchor.confidence ?? 0.5,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if( scopes.includes('actions') ){
|
|
44
|
+
const composed = _composeActions( neighbors, weights )
|
|
45
|
+
out.actions = composed.actions
|
|
46
|
+
out.reasoning = composed.reasoning
|
|
47
|
+
out.confidence = composed.confidence
|
|
48
|
+
} else {
|
|
49
|
+
// Actions are required downstream — fall back to the anchor's verbatim actions.
|
|
50
|
+
out.actions = _clone( anchor.actions ?? [] )
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if( scopes.includes('goals') )
|
|
54
|
+
out.newGoals = _composeGoals( neighbors, weights )
|
|
55
|
+
|
|
56
|
+
if( scopes.includes('beliefs') )
|
|
57
|
+
out.newBeliefs = _composeBeliefs( neighbors, weights )
|
|
58
|
+
|
|
59
|
+
return out
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── Weight computation ─────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
function _softmaxWeights( neighbors: ScoredNeighbor[], tau: number ): number[] {
|
|
65
|
+
const t = tau > 0 ? tau : 1e-6
|
|
66
|
+
const sims = neighbors.map( n => n.similarity )
|
|
67
|
+
const maxSim = Math.max( ...sims )
|
|
68
|
+
const exps = sims.map( s => Math.exp( ( s - maxSim ) / t ) ) // shift for stability
|
|
69
|
+
const sum = exps.reduce( ( a, b ) => a + b, 0 )
|
|
70
|
+
return exps.map( e => ( sum === 0 ? 1 / exps.length : e / sum ) )
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── ACTIONS: weighted type vote + verbatim copy ────────────
|
|
74
|
+
|
|
75
|
+
function _composeActions(
|
|
76
|
+
neighbors: ScoredNeighbor[],
|
|
77
|
+
weights: number[],
|
|
78
|
+
): { actions: ExecutiveOutputFull['actions']; reasoning: string; confidence: number } {
|
|
79
|
+
// Vote on each neighbor's primary (first) action type.
|
|
80
|
+
const typeWeight = new Map<string, number>()
|
|
81
|
+
for( let i = 0; i < neighbors.length; i++ ){
|
|
82
|
+
const acts = neighbors[ i ]!.pattern.output.actions ?? []
|
|
83
|
+
const primary = acts[ 0 ]?.type
|
|
84
|
+
if( primary === undefined ) continue
|
|
85
|
+
typeWeight.set( primary, ( typeWeight.get( primary ) ?? 0 ) + ( weights[ i ] ?? 0 ) )
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Winning type — deterministic: highest weight, ties broken by neighbor order
|
|
89
|
+
// (the first neighbor to reach the max keeps it, and neighbors are best-first).
|
|
90
|
+
let winningType: string | null = null
|
|
91
|
+
let bestWeight = -1
|
|
92
|
+
for( let i = 0; i < neighbors.length; i++ ){
|
|
93
|
+
const primary = neighbors[ i ]!.pattern.output.actions?.[ 0 ]?.type
|
|
94
|
+
if( primary === undefined ) continue
|
|
95
|
+
const w = typeWeight.get( primary ) ?? 0
|
|
96
|
+
if( w > bestWeight ){ bestWeight = w; winningType = primary }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Copy the full action list from the highest-weight neighbor whose primary
|
|
100
|
+
// action type matches the winner — verbatim, so text fields stay coherent.
|
|
101
|
+
let source = neighbors[ 0 ]!
|
|
102
|
+
for( let i = 0; i < neighbors.length; i++ ){
|
|
103
|
+
if( neighbors[ i ]!.pattern.output.actions?.[ 0 ]?.type === winningType ){
|
|
104
|
+
source = neighbors[ i ]!
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const src = source.pattern.output
|
|
110
|
+
return {
|
|
111
|
+
actions: _clone( src.actions ?? [] ),
|
|
112
|
+
reasoning: src.reasoning ?? '',
|
|
113
|
+
confidence: src.confidence ?? 0.5,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── GOALS: merge by description, mean priority (Phase 2) ────
|
|
118
|
+
|
|
119
|
+
function _composeGoals(
|
|
120
|
+
neighbors: ScoredNeighbor[],
|
|
121
|
+
weights: number[],
|
|
122
|
+
): ExecutiveOutputFull['newGoals'] {
|
|
123
|
+
type Agg = {
|
|
124
|
+
weight: number
|
|
125
|
+
priority: number
|
|
126
|
+
tags: string[]
|
|
127
|
+
completionType: string
|
|
128
|
+
completionCondition?: string
|
|
129
|
+
bestW: number
|
|
130
|
+
}
|
|
131
|
+
const byDesc = new Map<string, Agg>()
|
|
132
|
+
|
|
133
|
+
for( let i = 0; i < neighbors.length; i++ ){
|
|
134
|
+
const w = weights[ i ] ?? 0
|
|
135
|
+
for( const g of neighbors[ i ]!.pattern.output.newGoals ?? [] ){
|
|
136
|
+
const cur = byDesc.get( g.description )
|
|
137
|
+
if( cur ){
|
|
138
|
+
cur.weight += w
|
|
139
|
+
cur.priority += g.priority * w
|
|
140
|
+
if( w > cur.bestW ){
|
|
141
|
+
cur.bestW = w
|
|
142
|
+
cur.tags = g.tags
|
|
143
|
+
cur.completionType = g.completionType
|
|
144
|
+
cur.completionCondition = g.completionCondition
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
byDesc.set( g.description, {
|
|
148
|
+
weight: w,
|
|
149
|
+
priority: g.priority * w,
|
|
150
|
+
tags: g.tags,
|
|
151
|
+
completionType: g.completionType,
|
|
152
|
+
completionCondition: g.completionCondition,
|
|
153
|
+
bestW: w,
|
|
154
|
+
} )
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const result: NonNullable<ExecutiveOutputFull['newGoals']> = []
|
|
160
|
+
for( const [ description, a ] of byDesc ){
|
|
161
|
+
result.push( {
|
|
162
|
+
description,
|
|
163
|
+
priority: a.weight === 0 ? 0 : a.priority / a.weight,
|
|
164
|
+
tags: [ ...a.tags ],
|
|
165
|
+
completionType: a.completionType,
|
|
166
|
+
...( a.completionCondition !== undefined ? { completionCondition: a.completionCondition } : {} ),
|
|
167
|
+
} )
|
|
168
|
+
}
|
|
169
|
+
result.sort( ( x, y ) => y.priority - x.priority )
|
|
170
|
+
return result.slice( 0, 3 )
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── BELIEFS: merge by statement, mean confidence (Phase 3) ─
|
|
174
|
+
|
|
175
|
+
function _composeBeliefs(
|
|
176
|
+
neighbors: ScoredNeighbor[],
|
|
177
|
+
weights: number[],
|
|
178
|
+
): ExecutiveOutputFull['newBeliefs'] {
|
|
179
|
+
type Agg = {
|
|
180
|
+
weight: number
|
|
181
|
+
confidence: number
|
|
182
|
+
category: string
|
|
183
|
+
evidence: 'single_observation' | 'recurring_pattern' | 'strong_pattern'
|
|
184
|
+
tags: string[]
|
|
185
|
+
bestW: number
|
|
186
|
+
}
|
|
187
|
+
const byStmt = new Map<string, Agg>()
|
|
188
|
+
|
|
189
|
+
for( let i = 0; i < neighbors.length; i++ ){
|
|
190
|
+
const w = weights[ i ] ?? 0
|
|
191
|
+
for( const b of neighbors[ i ]!.pattern.output.newBeliefs ?? [] ){
|
|
192
|
+
const cur = byStmt.get( b.statement )
|
|
193
|
+
if( cur ){
|
|
194
|
+
cur.weight += w
|
|
195
|
+
cur.confidence += b.confidence * w
|
|
196
|
+
if( w > cur.bestW ){
|
|
197
|
+
cur.bestW = w
|
|
198
|
+
cur.category = b.category
|
|
199
|
+
cur.evidence = b.evidence
|
|
200
|
+
cur.tags = b.tags
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
byStmt.set( b.statement, {
|
|
204
|
+
weight: w,
|
|
205
|
+
confidence: b.confidence * w,
|
|
206
|
+
category: b.category,
|
|
207
|
+
evidence: b.evidence,
|
|
208
|
+
tags: b.tags,
|
|
209
|
+
bestW: w,
|
|
210
|
+
} )
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const result: NonNullable<ExecutiveOutputFull['newBeliefs']> = []
|
|
216
|
+
for( const [ statement, a ] of byStmt ){
|
|
217
|
+
result.push( {
|
|
218
|
+
statement,
|
|
219
|
+
category: a.category,
|
|
220
|
+
confidence: a.weight === 0 ? 0 : a.confidence / a.weight,
|
|
221
|
+
evidence: a.evidence,
|
|
222
|
+
tags: [ ...a.tags ],
|
|
223
|
+
} )
|
|
224
|
+
}
|
|
225
|
+
return result
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ── Deterministic deep clone for verbatim-copied blocks ────
|
|
229
|
+
|
|
230
|
+
function _clone<T>( v: T ): T {
|
|
231
|
+
return JSON.parse( JSON.stringify( v ) ) as T
|
|
232
|
+
}
|