@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
package/src/cognition/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type ModelPrice,
|
|
14
14
|
} from '#cognition/utilities/token.tracker'
|
|
15
15
|
|
|
16
|
+
import type { VectorMemoryAdapter } from '#memory/vector.adapter'
|
|
16
17
|
import { EnergyRegulator, type EnergyRegulatorConfig } from '#faculties/energy.regulator'
|
|
17
18
|
import { SleepPressureRegulator, type SleepPressureConfig } from '#faculties/sleep.pressure.regulator'
|
|
18
19
|
import { AttentionAllocator, type AttentionAllocatorConfig } from '#faculties/attention.allocator'
|
|
@@ -256,6 +257,12 @@ export type EngineRegistry = {
|
|
|
256
257
|
affectiveBlender: AffectiveBlender
|
|
257
258
|
workingMemory: WorkingMemory
|
|
258
259
|
episodicConsolidator: EpisodicConsolidator
|
|
260
|
+
/**
|
|
261
|
+
* The vector index, when semantic recall is configured. Exposed so shutdown can
|
|
262
|
+
* FLUSH it: it lives outside the state snapshot and previously persisted only from
|
|
263
|
+
* a debounce timer no shutdown path awaited, so it died with the process.
|
|
264
|
+
*/
|
|
265
|
+
vectorMemory: VectorMemoryAdapter | null
|
|
259
266
|
semanticIntegrator: SemanticIntegrator
|
|
260
267
|
spacedRepetition: SpacedRepetition
|
|
261
268
|
forgettingCurve: ForgettingCurve
|
|
@@ -18,7 +18,7 @@ export interface Instruction {
|
|
|
18
18
|
deadline?: number
|
|
19
19
|
/** Constraints on how to execute */
|
|
20
20
|
constraints?: string[]
|
|
21
|
-
/** Context
|
|
21
|
+
/** Context — why this instruction was given */
|
|
22
22
|
context: string
|
|
23
23
|
/** Whether the Will can refuse */
|
|
24
24
|
isOverridable: boolean
|
|
@@ -302,15 +302,24 @@ export class DefaultVectorMemoryAdapter implements VectorMemoryAdapter {
|
|
|
302
302
|
if( victims.length > 0 ) this._dirty = true
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Throttle, NOT a debounce. The previous version cleared and re-armed the timer on
|
|
307
|
+
* every index(), so it only ever fired after 5s of complete inactivity — and a mind
|
|
308
|
+
* consolidating steadily indexes far more often than that, so the write was pushed
|
|
309
|
+
* back indefinitely and the index never reached disk while it was awake.
|
|
310
|
+
*
|
|
311
|
+
* A pending timer is now left alone: the first write after a quiet period sets the
|
|
312
|
+
* deadline, and everything indexed within the window rides along on it. Persist is
|
|
313
|
+
* bounded at 5s from the FIRST pending change rather than the last.
|
|
314
|
+
*/
|
|
305
315
|
private _schedulePersist(): void {
|
|
306
|
-
if( this._persistDebounceTimer )
|
|
307
|
-
clearTimeout( this._persistDebounceTimer )
|
|
316
|
+
if( this._persistDebounceTimer ) return
|
|
308
317
|
|
|
309
318
|
this._persistDebounceTimer = setTimeout( () => {
|
|
319
|
+
this._persistDebounceTimer = null
|
|
310
320
|
this.persist().catch( err => {
|
|
311
321
|
logger.error(`[VectorMemoryAdapter] Persist failed:`, err )
|
|
312
322
|
} )
|
|
313
|
-
this._persistDebounceTimer = null
|
|
314
323
|
}, 5000 )
|
|
315
324
|
}
|
|
316
325
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import type { TokenTracker } from '#cognition/utilities/token.tracker'
|
|
15
15
|
import type { LLMCallFunction } from '#cognition/utilities/token.tracker'
|
|
16
|
+
import { LLMSemaphore, withGate } from '#llm/gate'
|
|
16
17
|
|
|
17
18
|
/** Embedding is only ever a read or a write. */
|
|
18
19
|
export type EmbedFunction = Extract<LLMCallFunction, 'recall' | 'index'>
|
|
@@ -44,16 +45,28 @@ export class OpenAICompatibleEmbedder implements EmbeddingProvider {
|
|
|
44
45
|
private _maxConcurrency: number
|
|
45
46
|
private _timeoutMs: number
|
|
46
47
|
private _tokenTracker: TokenTracker | null
|
|
48
|
+
/**
|
|
49
|
+
* Own gate — the same LLMSemaphore the LLM calls use, on a separate instance so
|
|
50
|
+
* embeddings and reasoning do not compete for one another's slots. It bounds the
|
|
51
|
+
* fan-out that produced the 10.7s tail, and `withGate` additionally retries a 429
|
|
52
|
+
* with backoff, which a bare `embed()` previously surfaced as a hard failure.
|
|
53
|
+
*/
|
|
54
|
+
private _gate: LLMSemaphore
|
|
47
55
|
|
|
48
56
|
constructor( config: {
|
|
49
57
|
modelName: string
|
|
50
58
|
dimensions: number
|
|
51
59
|
apiUrl: string
|
|
52
60
|
apiKey?: string | null
|
|
53
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Max embedding requests in flight at once — across ALL callers, not just one
|
|
63
|
+
* embedBatch(). Default 4, chosen from measured provider behaviour rather than
|
|
64
|
+
* taste: gemini-embedding-001 answers a lone request in ~1.1s, but queues hard
|
|
65
|
+
* under fan-out — at 8 in flight the slowest three took 10.7s (all HTTP 200, no
|
|
66
|
+
* 429, simply serialized). That tail is what made recall exceed its 5s budget
|
|
67
|
+
* and return "no recall" while a mind with six live facets was asking.
|
|
68
|
+
*/
|
|
54
69
|
maxConcurrency?: number
|
|
55
|
-
/** @deprecated use maxConcurrency — kept as its fallback for back-compat. */
|
|
56
|
-
batchSize?: number
|
|
57
70
|
/** Per-request timeout in ms before the connection is aborted. Default 30s. */
|
|
58
71
|
timeoutMs?: number
|
|
59
72
|
/**
|
|
@@ -67,12 +80,24 @@ export class OpenAICompatibleEmbedder implements EmbeddingProvider {
|
|
|
67
80
|
this.dimensions = config.dimensions
|
|
68
81
|
this._apiUrl = config.apiUrl
|
|
69
82
|
this._apiKey = config.apiKey ?? null
|
|
70
|
-
this._maxConcurrency = Math.max( 1, config.maxConcurrency ??
|
|
83
|
+
this._maxConcurrency = Math.max( 1, config.maxConcurrency ?? 4 )
|
|
84
|
+
this._gate = new LLMSemaphore( this._maxConcurrency )
|
|
71
85
|
this._timeoutMs = config.timeoutMs ?? 30_000
|
|
72
86
|
this._tokenTracker = config.tokenTracker ?? null
|
|
73
87
|
}
|
|
74
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Embed one item, gated. Every caller funnels through here — a facet building a
|
|
91
|
+
* prompt, the master recalling, the consolidator indexing — so the gate is the
|
|
92
|
+
* only place total in-flight fan-out is bounded. Waiting for a slot is strictly
|
|
93
|
+
* better than the alternative it replaces: an ungated request that returns after
|
|
94
|
+
* the recall budget has already expired is a request whose answer is thrown away.
|
|
95
|
+
*/
|
|
75
96
|
async embed( content: unknown, fn: EmbedFunction = 'recall'): Promise<number[]> {
|
|
97
|
+
return withGate( () => this._embedOnce( content, fn ), `embed:${ this.modelName }`, this._gate )
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private async _embedOnce( content: unknown, fn: EmbedFunction ): Promise<number[]> {
|
|
76
101
|
let response: Response
|
|
77
102
|
try {
|
|
78
103
|
response = await fetch(`${this._apiUrl}/embeddings`, {
|
|
@@ -110,6 +135,21 @@ export class OpenAICompatibleEmbedder implements EmbeddingProvider {
|
|
|
110
135
|
if( !Array.isArray( embedding ) || embedding.length === 0 )
|
|
111
136
|
throw new Error(`Embedding response was empty or malformed for model ${this.modelName}`)
|
|
112
137
|
|
|
138
|
+
// The configured width must match what the provider actually returns. This class
|
|
139
|
+
// sends no `dimensions` param, so the index is sized from config alone — and a
|
|
140
|
+
// wrong number does not fail, it silently builds an index that can never match.
|
|
141
|
+
// Providers differ per model family and change defaults between versions, so the
|
|
142
|
+
// number is checked against reality once rather than trusted. Failing here is safe:
|
|
143
|
+
// indexing degrades to "deferred" and recall to "no recall", both already
|
|
144
|
+
// best-effort, and the message carries the value to set.
|
|
145
|
+
if( embedding.length !== this.dimensions )
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Embedding width mismatch for ${ this.modelName }: provider returned ${ embedding.length } ` +
|
|
148
|
+
`dimensions, index is configured for ${ this.dimensions }. ` +
|
|
149
|
+
`Set WILL_EMBEDDING_DIMENSIONS=${ embedding.length } (and delete any existing ` +
|
|
150
|
+
`vector_index built at the old width).`
|
|
151
|
+
)
|
|
152
|
+
|
|
113
153
|
// Meter embedding token usage (input-only — embeddings have no completion).
|
|
114
154
|
// Recorded under the 'embedding' category so per-Will dashboards can split
|
|
115
155
|
// memory-vector spend from LLM reasoning spend.
|
|
@@ -122,6 +162,7 @@ export class OpenAICompatibleEmbedder implements EmbeddingProvider {
|
|
|
122
162
|
totalTokens: usedTok,
|
|
123
163
|
category: 'embedding',
|
|
124
164
|
attribute: 'memory',
|
|
165
|
+
process: 'cog', // background: no deliberation happens here
|
|
125
166
|
function: fn, // 'recall' (query) | 'index' (write)
|
|
126
167
|
scope: this.modelName,
|
|
127
168
|
tick: 0,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/percept.entity.ts — one shape for "something reached me"
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// A `percept` entity is the staging area every downstream consumer of afference
|
|
6
|
+
// reads. Five places write one and none of them agreed on what one is:
|
|
7
|
+
//
|
|
8
|
+
// exteroception tick ✓ provenance ✓ the complete one
|
|
9
|
+
// outbox.controller tick ✗ provenance ✓
|
|
10
|
+
// escalation.buffer tick ✓ provenance ✗ (x2)
|
|
11
|
+
// stem/index.ts tick ✗ provenance ✗ the wake percept
|
|
12
|
+
//
|
|
13
|
+
// Both omissions are silent and both cost something real:
|
|
14
|
+
//
|
|
15
|
+
// • NO `tick` — `exteroception._collectStalePerceptIds` is the ONLY sweeper of
|
|
16
|
+
// this type, and it collects only entities whose `metadata.tick` is a
|
|
17
|
+
// number. Everything else is immortal. `msg-delivered-<id>` therefore leaks
|
|
18
|
+
// one entity per message the mind ever successfully sends, and the wake
|
|
19
|
+
// percept tells the executive "I was offline for 3 hours" for the rest of
|
|
20
|
+
// the mind's life.
|
|
21
|
+
// • NO `provenance` — `action.selector`'s rupture gate counts only percepts
|
|
22
|
+
// tagged `'exafferent'`, so an untagged percept can never rupture a
|
|
23
|
+
// commitment, exactly as the mind's own echo cannot. A mind waking after
|
|
24
|
+
// hours offline cannot be ruptured by noticing that.
|
|
25
|
+
//
|
|
26
|
+
// Neither is a bug in the writers. They are a bug in there being no shape to
|
|
27
|
+
// write: every one of them hand-rolled a metadata literal, and a literal cannot
|
|
28
|
+
// forget a field it was never asked for. This is the shape. It makes `tick` and
|
|
29
|
+
// `provenance` REQUIRED, so the sweeper's precondition and the rupture gate's
|
|
30
|
+
// precondition are both structural rather than remembered.
|
|
31
|
+
//
|
|
32
|
+
// SIGNAL_BOUNDARY P0. Own the contract before widening it — the sense door is
|
|
33
|
+
// about to become a sixth writer, and it must not invent a sixth variant.
|
|
34
|
+
|
|
35
|
+
import type { SignalProvenance } from '#senses/provenance'
|
|
36
|
+
|
|
37
|
+
export const PERCEPT_TYPE = 'percept'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* How long a `percept` survives before `Exteroception` sweeps it. Not a
|
|
41
|
+
* durability window — a *staging* window. Persistence happens downstream
|
|
42
|
+
* (WorkingMemory → EpisodicConsolidator → vector); a percept's job is to be
|
|
43
|
+
* seen once by the faculties that run each tick, then get out of the way.
|
|
44
|
+
*/
|
|
45
|
+
export const PERCEPT_STALE_AFTER_TICKS = 2
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* How much of a percept's `summary` survives.
|
|
49
|
+
*
|
|
50
|
+
* 100 because that is what `exteroception._summarizeEntity` has always used —
|
|
51
|
+
* adopted rather than chosen, so naming it changes no behaviour. It is now one
|
|
52
|
+
* constant instead of a literal per writer, which is the point: the sizing
|
|
53
|
+
* question is real and open (SIGNAL_BOUNDARY §4 asks it of 120/300/700 too, and
|
|
54
|
+
* notes that none of those was ever a budget decision), and answering it should
|
|
55
|
+
* be a one-line change in one place rather than an archaeology exercise.
|
|
56
|
+
*/
|
|
57
|
+
export const PERCEPT_SUMMARY_CAP = 100
|
|
58
|
+
|
|
59
|
+
/** What every percept must say, whatever wrote it. */
|
|
60
|
+
export interface PerceptFacts {
|
|
61
|
+
/** Deterministic and unique. Never `wallClock()` — this lives in state (R2). */
|
|
62
|
+
id: string
|
|
63
|
+
/** The tick it arrived on. REQUIRED: without it the entity is never swept. */
|
|
64
|
+
tick: number
|
|
65
|
+
/** 0–1. The rupture gate reads this. */
|
|
66
|
+
salience: number
|
|
67
|
+
/** Coarse kind, for grouping — 'message-delivery', 'system', 'undertaking'… */
|
|
68
|
+
category: string
|
|
69
|
+
/** The one field the executive prompt renders. If it is not here, it is unread. */
|
|
70
|
+
summary: string
|
|
71
|
+
/** REQUIRED: untagged means unrupturable. See `SignalProvenance`. */
|
|
72
|
+
provenance: SignalProvenance
|
|
73
|
+
/** The intent this is the consequence of, when `provenance` is `'reafferent'`. */
|
|
74
|
+
sourceIntentId?: string
|
|
75
|
+
/** The world entity this is about, where there is one. */
|
|
76
|
+
entityId?: string
|
|
77
|
+
/** What happened to it — 'delivered', 'removed', 'changed'… */
|
|
78
|
+
changeType?: string
|
|
79
|
+
/** What it FELT like, and how much that says about it (registry #5). */
|
|
80
|
+
valence?: number
|
|
81
|
+
valenceSource?: string
|
|
82
|
+
/**
|
|
83
|
+
* What a host sent, whole. Carried into state so it survives to working
|
|
84
|
+
* memory, recall and the prompt — `summary` is a label the engine wrote, and
|
|
85
|
+
* a mind reasoning only from labels is reasoning from somebody else's
|
|
86
|
+
* conclusions.
|
|
87
|
+
*/
|
|
88
|
+
data?: unknown
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The write-side entity shape `stateManager.setEntity` accepts. */
|
|
92
|
+
export interface PerceptEntity {
|
|
93
|
+
id: string
|
|
94
|
+
type: typeof PERCEPT_TYPE
|
|
95
|
+
metadata: Record<string, unknown>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Build a `percept` entity. `extra` carries a writer's own fields (`messageId`,
|
|
100
|
+
* `facetId`, `offlineMs`…) and cannot overwrite the core: a writer that could
|
|
101
|
+
* clobber its own `tick` or `provenance` is back where it started.
|
|
102
|
+
*/
|
|
103
|
+
export function perceptEntity( facts: PerceptFacts, extra: Record<string, unknown> = {} ): PerceptEntity {
|
|
104
|
+
return {
|
|
105
|
+
id: facts.id,
|
|
106
|
+
type: PERCEPT_TYPE,
|
|
107
|
+
metadata: {
|
|
108
|
+
...extra,
|
|
109
|
+
tick: facts.tick,
|
|
110
|
+
salience: facts.salience,
|
|
111
|
+
category: facts.category,
|
|
112
|
+
summary: facts.summary,
|
|
113
|
+
provenance: facts.provenance,
|
|
114
|
+
...( facts.sourceIntentId !== undefined ? { sourceIntentId: facts.sourceIntentId } : {} ),
|
|
115
|
+
...( facts.entityId !== undefined ? { entityId: facts.entityId } : {} ),
|
|
116
|
+
...( facts.changeType !== undefined ? { changeType: facts.changeType } : {} ),
|
|
117
|
+
...( facts.valence !== undefined ? { valence: facts.valence } : {} ),
|
|
118
|
+
...( facts.valenceSource !== undefined ? { valenceSource: facts.valenceSource } : {} ),
|
|
119
|
+
...( facts.data !== undefined ? { data: facts.data } : {} ),
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -118,6 +118,7 @@ const PRIOR_DESCRIPTIONS: Record<string, { lower: string; raise: string }> = {
|
|
|
118
118
|
'engine-config-inhibition.baseInhibitionStrength': { lower: 'acting on impulse more freely', raise: 'holding myself in check more firmly before acting' },
|
|
119
119
|
'engine-config-self-model.minNewExperiences': { lower: 're-evaluating who I am on less new experience', raise: 'requiring more new experience before re-evaluating who I am' },
|
|
120
120
|
'engine-config-attention.shiftInertia': { lower: 'shifting my attention more readily', raise: 'holding my attention more fixedly' },
|
|
121
|
+
'engine-config-attention.maxFoci': { lower: 'attending to one thing at a time, narrowly', raise: 'keeping several things in view at once' },
|
|
121
122
|
'engine-config-goal-manager.gritPriority': { lower: 'refusing to give up on more of what matters to me', raise: 'letting go of goals more readily' },
|
|
122
123
|
'engine-config-goal-manager.gritPatienceScale': { lower: 'losing patience with stuck goals sooner', raise: 'staying the course on hard goals far longer' },
|
|
123
124
|
'engine-config-goal-manager.frustrationTolerance': { lower: 'giving up faster when frustrated', raise: 'holding steady through frustration' },
|
|
@@ -129,6 +130,7 @@ const PRIOR_DESCRIPTIONS: Record<string, { lower: string; raise: string }> = {
|
|
|
129
130
|
'engine-config-executive.riskTolerance': { lower: 'playing it safer', raise: 'taking bigger risks' },
|
|
130
131
|
'engine-config-frustration.irritabilityRate': { lower: 'letting frustration snowball into a bad mood more slowly', raise: 'getting wound up into a bad mood faster' },
|
|
131
132
|
'engine-config-executive.deliberateThreshold': { lower: 'stopping to think things through more readily', raise: 'going with my gut more, deliberating less' },
|
|
133
|
+
'engine-config-executive.maxFacets': { lower: 'keeping fewer things going at once, one at a time', raise: 'holding more conversations and threads at once' },
|
|
132
134
|
'engine-config-reward.socialWeight': { lower: 'caring less about social warmth', raise: 'finding warmth and connection more rewarding' },
|
|
133
135
|
'engine-config-frustration.angerReactivity': { lower: 'letting slights go, yielding rather than bristling', raise: 'bristling harder when I feel wronged' },
|
|
134
136
|
'engine-config-novelty.significanceThreshold': { lower: 'noticing what is new and unusual more readily', raise: 'needing more for something to strike me as new' },
|
|
@@ -143,6 +145,10 @@ const PRIOR_DESCRIPTIONS: Record<string, { lower: string; raise: string }> = {
|
|
|
143
145
|
'engine-config-action-selector.switchCost': { lower: 'dropping what I am doing for a new pull more easily', raise: 'seeing an action through, harder to knock off course once underway' },
|
|
144
146
|
'engine-config-action-selector.riskWeight': { lower: 'weighing the downside of what I do less — acting bolder', raise: 'weighing what could go wrong more heavily before I act' },
|
|
145
147
|
'engine-config-action-selector.noveltyWeight': { lower: 'feeling less pull toward the untried', raise: 'drawn more strongly to do the untried and unpracticed' },
|
|
148
|
+
'engine-config-action-selector.repeatDamping': { lower: 'following up sooner when I have had no answer', raise: 'giving people room after I have said my piece' },
|
|
149
|
+
'engine-config-action-selector.repeatWindowTicks': { lower: 'coming back to something sooner after I have said it', raise: 'letting what I have said stand for longer before returning to it' },
|
|
150
|
+
'engine-config-action-selector.replyWindowTicks': { lower: 'reading a silence as an answer sooner', raise: 'giving someone longer before I take their quiet as telling me anything' },
|
|
151
|
+
'engine-config-action-selector.socialWeight': { lower: 'reaching for people regardless of whether they answer me', raise: 'drawn toward the people who actually answer me' },
|
|
146
152
|
'engine-config-moral.eventThreshold': { lower: 'holding myself to my principles more sharply', raise: 'letting moral lapses weigh on me less' },
|
|
147
153
|
'engine-config-frustration.decayRate': { lower: 'staying frustrated for longer after a setback', raise: 'shaking off frustration and bouncing back faster' },
|
|
148
154
|
'engine-config-reward.socialWarmthBoost': { lower: 'being warmed less by a kind exchange', raise: 'being warmed more by every kind exchange' },
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/sense.boundary.ts — where I end and the world begins
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// A body needs no rule saying "do not see your own premotor cortex." You do not
|
|
6
|
+
// see it because the retina sits ON the boundary and motor planning is inside
|
|
7
|
+
// it. Efference reaches you as a different signal, in a different modality,
|
|
8
|
+
// already marked as yours — which this engine knows: that is what EXAFFERENCE
|
|
9
|
+
// P1/P2 built.
|
|
10
|
+
//
|
|
11
|
+
// Will has no such boundary. Cognition and world share one `state.entities` map,
|
|
12
|
+
// so the mind's own bookkeeping sits in the same place as the things it is
|
|
13
|
+
// bookkeeping ABOUT, and Exteroception — the outward sense — walks the lot.
|
|
14
|
+
//
|
|
15
|
+
// THE COST, MEASURED. A mind booted offline for 300 quiet ticks — no host, no
|
|
16
|
+
// channel, nothing outside it at all — produced 36,721 percepts, every one about
|
|
17
|
+
// itself:
|
|
18
|
+
//
|
|
19
|
+
// 17802 removed its own affordances being torn down each tick
|
|
20
|
+
// 16950 affordance its own affordances being rebuilt each tick
|
|
21
|
+
// 546 calibration.state
|
|
22
|
+
// 496 agency.intent
|
|
23
|
+
// 287 agency.outcome
|
|
24
|
+
// 286 agency.skill
|
|
25
|
+
// 135 action.unresolved
|
|
26
|
+
// 120 engine.config its own configuration
|
|
27
|
+
// 96 attention.demand
|
|
28
|
+
// 3 will.identity its own identity entity
|
|
29
|
+
//
|
|
30
|
+
// `maxPerceptsPerTick` is 50. The affordance field alone churns ~116 entities a
|
|
31
|
+
// tick, so the sensory cap was consumed by self-noise before the world said
|
|
32
|
+
// anything — and nothing downstream filters by category, so working memory, the
|
|
33
|
+
// novelty detector, the attention allocator and episodic consolidation all ate
|
|
34
|
+
// it. The visible symptom was elsewhere: a fresh Will proceduralized `inspect`
|
|
35
|
+
// to habit 0.64 within fifteen ticks and spent five of its first eight decisions
|
|
36
|
+
// examining its own affordance entities, because a percept-bound act offered
|
|
37
|
+
// against phantom percepts is a real act aimed at nothing.
|
|
38
|
+
//
|
|
39
|
+
// WHY IT DRIFTED. The boundary was a denylist living inside the sense
|
|
40
|
+
// (`internalTypes`), correct for the faculties it shipped beside in v0.1.0 and
|
|
41
|
+
// silently wrong for every entity type invented after. `git log -L` on that
|
|
42
|
+
// block shows two edits in five weeks — EXAFFERENCE P2 and P4 — each adding the
|
|
43
|
+
// one agency type in front of its author at that moment. A hand-kept list is
|
|
44
|
+
// correct for whatever you were last thinking about.
|
|
45
|
+
//
|
|
46
|
+
// THE ASYMMETRY THAT MAKES THIS TRACTABLE. The mind's own types are a CLOSED
|
|
47
|
+
// set: it knows its own anatomy. The world's types are OPEN and unknowable —
|
|
48
|
+
// that is the whole point of a container anything can rent. So enumerate the
|
|
49
|
+
// self, and let everything else be world by default. Openness is preserved
|
|
50
|
+
// exactly where it must be: a host introduces any entity type, any shape, and
|
|
51
|
+
// the mind perceives it, with no act narrowed and no schema gated.
|
|
52
|
+
//
|
|
53
|
+
// Two sources, unioned:
|
|
54
|
+
// • MIND_OWN_ENTITY_TYPES — the anatomy this package ships.
|
|
55
|
+
// • each registered engine's `writes` — so a tenant that brings its OWN
|
|
56
|
+
// cognitive engine declares its own machinery beside the code that writes
|
|
57
|
+
// it, and gets this right without editing the container.
|
|
58
|
+
//
|
|
59
|
+
// The guard that keeps it true is behavioural, not a source scanner:
|
|
60
|
+
// `sense.boundary.test.ts` boots a mind into an empty world and asserts it
|
|
61
|
+
// perceives nothing. A new engine writing a new undeclared type fails it.
|
|
62
|
+
// ─────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
import { CONSEQUENCE_TYPE, ENACTED_TYPE } from '#agency/consequence'
|
|
65
|
+
import { AVAILABILITY_ENTITY_TYPE } from '#agency/schemas/repertoire'
|
|
66
|
+
import { REVOCATION_TYPE } from '#agency/revocation'
|
|
67
|
+
import { SETTLEMENT_TYPE } from '#agency/settlement'
|
|
68
|
+
import { ACTION_RECORD_TYPE } from '#faculties/executive.engine/action.record'
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Entity types that ARE the mind — written by its own engines about its own
|
|
72
|
+
* operation. Not perceptible: a mind does not encounter its own machinery as an
|
|
73
|
+
* event in the world.
|
|
74
|
+
*
|
|
75
|
+
* Grouped by the faculty that writes them so a reader can check the list
|
|
76
|
+
* against the anatomy. Everything absent here is world.
|
|
77
|
+
*/
|
|
78
|
+
export const MIND_OWN_ENTITY_TYPES: ReadonlySet<string> = new Set([
|
|
79
|
+
// ── perception ────────────────────────────────────────────────
|
|
80
|
+
// Percepts about percepts are the original feedback loop this guarded.
|
|
81
|
+
'percept', 'percept.social',
|
|
82
|
+
|
|
83
|
+
// ── attention, interoception, control ─────────────────────────
|
|
84
|
+
'interoception', 'attention.focus', 'attention.demand',
|
|
85
|
+
'task.focus', 'decision.record', 'self_observation',
|
|
86
|
+
// What became of what it did. Undeclared, a mind perceives its own history as
|
|
87
|
+
// events in the world — which is how #127 was caught, recursively.
|
|
88
|
+
ACTION_RECORD_TYPE,
|
|
89
|
+
|
|
90
|
+
// ── memory ────────────────────────────────────────────────────
|
|
91
|
+
'working_memory.item', 'episodic_memory', 'spaced_repetition_record',
|
|
92
|
+
'belief', 'belief.integrate',
|
|
93
|
+
|
|
94
|
+
// ── deliberative structure ────────────────────────────────────
|
|
95
|
+
'goal', 'plan', 'plan.prior',
|
|
96
|
+
|
|
97
|
+
// ── narrative + metacognition ─────────────────────────────────
|
|
98
|
+
'narrative_chapter', 'introspection', 'self_narrative', 'cognitive_bias',
|
|
99
|
+
'calibration.state', 'executive.summary', 'executive.cache',
|
|
100
|
+
|
|
101
|
+
// ── affect + social models ────────────────────────────────────
|
|
102
|
+
// A dossier is the mind's record OF someone, not the someone. The person
|
|
103
|
+
// arrives through audition and social perception; the dossier is what the
|
|
104
|
+
// mind then holds about them, and re-perceiving it double-counts.
|
|
105
|
+
'affect.blends', 'empathic_state', 'attachment.bond',
|
|
106
|
+
'theory_of_mind', 'reputation',
|
|
107
|
+
'known-entity', 'known-entity-alias',
|
|
108
|
+
|
|
109
|
+
// ── conversation records ──────────────────────────────────────
|
|
110
|
+
// SocialPerception is the sense that owns these (it reads
|
|
111
|
+
// `conversation.received` and emits `percept.social` from it, then sweeps it).
|
|
112
|
+
// Exteroception perceiving them too was the same turn counted twice.
|
|
113
|
+
'conversation.received', 'conversation.sent',
|
|
114
|
+
|
|
115
|
+
// ── agency ────────────────────────────────────────────────────
|
|
116
|
+
// The whole pipeline: the field it synthesizes, what it committed to, what
|
|
117
|
+
// came back, what it learned, and what it merely imagined.
|
|
118
|
+
'affordance', 'agency.intent', 'agency.outcome', 'agency.skill',
|
|
119
|
+
'agency.schema', 'ideomotor.intent',
|
|
120
|
+
// What it HAS DONE — the enaction footprint satiation reads to know it has
|
|
121
|
+
// already tried this. Undeclared, it was the loudest thing in the mind's
|
|
122
|
+
// perceptual field: measured on a live Will, `New agency.enacted: agency-
|
|
123
|
+
// enacted-discord_lookup_…` sat at salience 0.5, ABOVE every real percept,
|
|
124
|
+
// and each enaction produced two of them — one when the record appeared, one
|
|
125
|
+
// when the retention sweep removed it. A mind watching its own footprints
|
|
126
|
+
// being laid down and swept away, and calling that the world.
|
|
127
|
+
ENACTED_TYPE,
|
|
128
|
+
// What it may currently do, and why not. The availability ledger is empty
|
|
129
|
+
// until a refusal lands (POLICY_REAFFERENCE P2), which is exactly why nothing
|
|
130
|
+
// caught it: a mind that has never been told no writes none of these, so the
|
|
131
|
+
// quiet path and every test that stays on it are blind to the omission. Give
|
|
132
|
+
// a Will a PolicyArbiter that refuses, and it starts perceiving its own
|
|
133
|
+
// permissions changing as events in the world.
|
|
134
|
+
AVAILABILITY_ENTITY_TYPE,
|
|
135
|
+
'action.unresolved', 'action.unaddressed',
|
|
136
|
+
CONSEQUENCE_TYPE, // forward-model records (EXAFFERENCE P1/P2)
|
|
137
|
+
REVOCATION_TYPE, // commitment tombstones (EXAFFERENCE P4)
|
|
138
|
+
SETTLEMENT_TYPE, // verdicts System 2 reached — having thought about it
|
|
139
|
+
|
|
140
|
+
// ── substrate ─────────────────────────────────────────────────
|
|
141
|
+
// Its configuration and its identity are constitutive of it, not events in
|
|
142
|
+
// its world. It had been perceiving both.
|
|
143
|
+
'engine.config', 'will.identity', 'effector.created',
|
|
144
|
+
'dream.activity',
|
|
145
|
+
])
|
|
146
|
+
|
|
147
|
+
/** An engine that declares the entity types it writes about the mind itself. */
|
|
148
|
+
export interface DeclaresWrites {
|
|
149
|
+
/**
|
|
150
|
+
* Entity types this engine writes as part of the mind's own operation.
|
|
151
|
+
*
|
|
152
|
+
* Declare here anything the mind should NOT re-encounter through its outward
|
|
153
|
+
* senses. Omit it for engines that write about the WORLD — a host engine
|
|
154
|
+
* maintaining rooms, documents, or sensor readings wants those perceived, and
|
|
155
|
+
* silence is the right default for them.
|
|
156
|
+
*/
|
|
157
|
+
readonly writes?: readonly string[]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The full endogenous set for a given assembly: the shipped anatomy plus
|
|
162
|
+
* whatever the registered engines declare.
|
|
163
|
+
*
|
|
164
|
+
* Cheap enough to call per tick, but Exteroception memoizes on the engine list
|
|
165
|
+
* so a 50-engine union isn't rebuilt in the perceptual hot path.
|
|
166
|
+
*/
|
|
167
|
+
export function endogenousTypes( engines: readonly DeclaresWrites[] ): ReadonlySet<string> {
|
|
168
|
+
let extra: Set<string> | null = null
|
|
169
|
+
for( const e of engines )
|
|
170
|
+
for( const t of e.writes ?? [] )
|
|
171
|
+
if( !MIND_OWN_ENTITY_TYPES.has( t ) )
|
|
172
|
+
( extra ??= new Set() ).add( t )
|
|
173
|
+
|
|
174
|
+
if( !extra ) return MIND_OWN_ENTITY_TYPES
|
|
175
|
+
return new Set([ ...MIND_OWN_ENTITY_TYPES, ...extra ])
|
|
176
|
+
}
|