@mindot/will 0.1.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/LICENSE +202 -0
- package/README.md +777 -0
- package/dist/index.d.ts +8144 -0
- package/dist/index.js +26231 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
- package/src/cognition/agency/access.grants.ts +59 -0
- package/src/cognition/agency/competence.codec.ts +89 -0
- package/src/cognition/agency/engines/action.selector.ts +462 -0
- package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
- package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
- package/src/cognition/agency/engines/instruction.intake.ts +54 -0
- package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
- package/src/cognition/agency/engines/reafference.engine.ts +241 -0
- package/src/cognition/agency/execution.primitives.ts +118 -0
- package/src/cognition/agency/index.ts +58 -0
- package/src/cognition/agency/proactive.communicator.ts +274 -0
- package/src/cognition/agency/reconcile.learning.ts +82 -0
- package/src/cognition/agency/schemas/external.ts +59 -0
- package/src/cognition/agency/schemas/innate.ts +111 -0
- package/src/cognition/agency/schemas/repertoire.ts +246 -0
- package/src/cognition/agency/selection.scoring.ts +191 -0
- package/src/cognition/agency/types.ts +165 -0
- package/src/cognition/bus.ts +391 -0
- package/src/cognition/completion.inbox.ts +86 -0
- package/src/cognition/config.mirror.entities.ts +475 -0
- package/src/cognition/conversation.memory.ts +81 -0
- package/src/cognition/event.log.ts +116 -0
- package/src/cognition/event.schemas.ts +568 -0
- package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
- package/src/cognition/faculties/affective.blender.ts +562 -0
- package/src/cognition/faculties/attachment.evaluator.ts +432 -0
- package/src/cognition/faculties/attention.allocator.ts +422 -0
- package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
- package/src/cognition/faculties/bias.detector.ts +363 -0
- package/src/cognition/faculties/circadian.oscillator.ts +294 -0
- package/src/cognition/faculties/confidence.calibrator.ts +324 -0
- package/src/cognition/faculties/dream.simulator.ts +251 -0
- package/src/cognition/faculties/empathy.simulator.ts +253 -0
- package/src/cognition/faculties/energy.regulator.ts +320 -0
- package/src/cognition/faculties/episodic.consolidator.ts +728 -0
- package/src/cognition/faculties/executive.engine/commands.ts +459 -0
- package/src/cognition/faculties/executive.engine/config.ts +46 -0
- package/src/cognition/faculties/executive.engine/context.ts +605 -0
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
- package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
- package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
- package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
- package/src/cognition/faculties/executive.engine/facet.ts +628 -0
- package/src/cognition/faculties/executive.engine/gating.ts +222 -0
- package/src/cognition/faculties/executive.engine/index.ts +6 -0
- package/src/cognition/faculties/executive.engine/messages.ts +102 -0
- package/src/cognition/faculties/executive.engine/parser.ts +380 -0
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
- package/src/cognition/faculties/executive.engine/types.ts +323 -0
- package/src/cognition/faculties/exteroception.ts +338 -0
- package/src/cognition/faculties/forgetting.curve.ts +202 -0
- package/src/cognition/faculties/frustration.evaluator.ts +280 -0
- package/src/cognition/faculties/goal.manager.ts +1008 -0
- package/src/cognition/faculties/inhibition.controller.ts +351 -0
- package/src/cognition/faculties/interoception.ts +417 -0
- package/src/cognition/faculties/introspection.engine.ts +246 -0
- package/src/cognition/faculties/known.entity.tracker.ts +439 -0
- package/src/cognition/faculties/loss.evaluator.ts +224 -0
- package/src/cognition/faculties/moral.evaluator.ts +437 -0
- package/src/cognition/faculties/novelty.detector.ts +254 -0
- package/src/cognition/faculties/persona.consolidator.ts +845 -0
- package/src/cognition/faculties/planning.engine/engine.ts +859 -0
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
- package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
- package/src/cognition/faculties/planning.engine/types.ts +143 -0
- package/src/cognition/faculties/reputation.tracker.ts +294 -0
- package/src/cognition/faculties/reward.evaluator.ts +304 -0
- package/src/cognition/faculties/self.model.updater.ts +677 -0
- package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
- package/src/cognition/faculties/semantic.engine/index.ts +6 -0
- package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
- package/src/cognition/faculties/semantic.engine/types.ts +53 -0
- package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
- package/src/cognition/faculties/social.perception.ts +333 -0
- package/src/cognition/faculties/spaced.repetition.ts +605 -0
- package/src/cognition/faculties/stress.regulator.ts +375 -0
- package/src/cognition/faculties/task.switcher.ts +239 -0
- package/src/cognition/faculties/theory.of.mind.ts +333 -0
- package/src/cognition/faculties/threat.evaluator.ts +312 -0
- package/src/cognition/faculties/working.memory.ts +406 -0
- package/src/cognition/generative.model.ts +344 -0
- package/src/cognition/heartbeat.ts +70 -0
- package/src/cognition/index.ts +291 -0
- package/src/cognition/instruction.handler.ts +146 -0
- package/src/cognition/memory/index.ts +35 -0
- package/src/cognition/memory/vector.adapter.ts +316 -0
- package/src/cognition/memory/vector.content.ts +47 -0
- package/src/cognition/memory/vector.embedder.ts +212 -0
- package/src/cognition/memory/vector.index.ts +459 -0
- package/src/cognition/memory/vector.types.ts +65 -0
- package/src/cognition/orchestrator.ts +142 -0
- package/src/cognition/persona.prior.ts +265 -0
- package/src/cognition/schema.registry.ts +145 -0
- package/src/cognition/senses/audition.engine/engine.ts +976 -0
- package/src/cognition/senses/audition.engine/salience.ts +59 -0
- package/src/cognition/senses/base.sense.engine.ts +117 -0
- package/src/cognition/senses/gustation.engine.ts +24 -0
- package/src/cognition/senses/index.ts +172 -0
- package/src/cognition/senses/olfaction.engine.ts +24 -0
- package/src/cognition/senses/somatosensation.engine.ts +23 -0
- package/src/cognition/senses/vision.engine.ts +23 -0
- package/src/cognition/types.ts +63 -0
- package/src/cognition/utilities/token.tracker.ts +492 -0
- package/src/core/abstracts.ts +60 -0
- package/src/core/async.engine.ts +539 -0
- package/src/core/clock.ts +196 -0
- package/src/core/completion.recorder.ts +122 -0
- package/src/core/conflict.detector.ts +140 -0
- package/src/core/distributed.ts +626 -0
- package/src/core/event.bus.ts +292 -0
- package/src/core/inbound.recorder.ts +100 -0
- package/src/core/index.ts +167 -0
- package/src/core/logger.ts +85 -0
- package/src/core/metrics.ts +107 -0
- package/src/core/orchestrator.ts +625 -0
- package/src/core/replay.ts +589 -0
- package/src/core/scenario.ts +120 -0
- package/src/core/serialization.ts +448 -0
- package/src/core/simulation.ts +197 -0
- package/src/core/snapshot.manager.ts +293 -0
- package/src/core/state.manager.ts +283 -0
- package/src/core/types.ts +274 -0
- package/src/core/utils.ts +82 -0
- package/src/core/wall.clock.ts +23 -0
- package/src/extensions/livestream.ext.ts +570 -0
- package/src/extensions/time.ext.ts +339 -0
- package/src/index.ts +91 -0
- package/src/llm/gate.ts +140 -0
- package/src/llm/index.ts +716 -0
- package/src/llm/summarizer.ts +170 -0
- package/src/llm/wire.contracts.ts +67 -0
- package/src/pma/eval.ts +651 -0
- package/src/pma/index.ts +1082 -0
- package/src/profiles/built-in.ts +7 -0
- package/src/profiles/companion.ts +28 -0
- package/src/profiles/company-brain.ts +54 -0
- package/src/profiles/customer-service.ts +30 -0
- package/src/profiles/game-npc.ts +20 -0
- package/src/profiles/index.ts +42 -0
- package/src/profiles/smart-home.ts +34 -0
- package/src/runners/coherence.runner.ts +49 -0
- package/src/runners/outreach.runner.ts +158 -0
- package/src/runners/social.runner.ts +182 -0
- package/src/runners/thin-shim.runner.ts +195 -0
- package/src/sdk/will.ts +334 -0
- package/src/stem/assembly.audit.ts +88 -0
- package/src/stem/distribution.ts +203 -0
- package/src/stem/guards/identity.coherence.ts +152 -0
- package/src/stem/guards/identity.guard.ts +227 -0
- package/src/stem/index.ts +1145 -0
- package/src/stem/mind.ts +1090 -0
- package/src/stem/tracts/ack.reconciler.ts +55 -0
- package/src/stem/tracts/biography.writer.ts +190 -0
- package/src/stem/tracts/effector.controller.ts +143 -0
- package/src/stem/tracts/health.reporter.ts +113 -0
- package/src/stem/tracts/inbound.queue.ts +54 -0
- package/src/stem/tracts/outbox.controller.ts +167 -0
- package/src/stem/tracts/outbox.writer.ts +133 -0
- package/src/stem/tracts/pma.controller.ts +109 -0
- package/src/stem/tracts/replay.controller.ts +177 -0
- package/src/stem/tracts/sensory.controller.ts +168 -0
- package/src/stem/tracts/session.logger.ts +157 -0
- package/src/stem/tracts/transport/index.ts +38 -0
- package/src/stem/tracts/transport/loopback.transport.ts +86 -0
- package/src/stem/tracts/transport/socketio.transport.ts +200 -0
- package/src/stem/tracts/transport/stream.transport.ts +152 -0
- package/src/stem/tracts/transport/types.ts +193 -0
- package/src/stem/tracts/transport.controller.ts +380 -0
- package/src/types.ts +116 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/executive.engine/types.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
import type { CognitiveBus } from '#cognition/bus'
|
|
6
|
+
import type { PlanStep } from '#cognition/faculties/planning.engine/engine'
|
|
7
|
+
|
|
8
|
+
// ── Full executive output ────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
export interface ExecutiveOutputFull {
|
|
11
|
+
actions: Array<{ type: string; reasoning: string; expectedOutcome: string; target?: string }>
|
|
12
|
+
reasoning: string
|
|
13
|
+
confidence: number
|
|
14
|
+
/** Plans — the executive controls lifecycle via status + action fields */
|
|
15
|
+
plans?: ExecutivePlanOutput[]
|
|
16
|
+
newBeliefs?: Array<{
|
|
17
|
+
statement: string
|
|
18
|
+
category: string
|
|
19
|
+
confidence: number
|
|
20
|
+
/**
|
|
21
|
+
* Evidence strength — replaces the hallucination-prone numeric count.
|
|
22
|
+
* The LLM picks a categorical label it can honestly assign; the runtime
|
|
23
|
+
* maps it to a numeric `supportingEpisodes` value for the belief store.
|
|
24
|
+
*/
|
|
25
|
+
evidence: 'single_observation' | 'recurring_pattern' | 'strong_pattern'
|
|
26
|
+
tags: string[]
|
|
27
|
+
}>
|
|
28
|
+
introspection?: {
|
|
29
|
+
explanation: string
|
|
30
|
+
identifiedBiases: string[]
|
|
31
|
+
lessonsLearned: string[]
|
|
32
|
+
recommendations: string[]
|
|
33
|
+
}
|
|
34
|
+
narrative?: string
|
|
35
|
+
narrativeThemes?: string[]
|
|
36
|
+
currentSelfView?: string
|
|
37
|
+
identityUpdates?: {
|
|
38
|
+
traits: Array<{ key: string; value: number }>
|
|
39
|
+
values: string[]
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* What the Will consciously learned about the *others* it is dealing with (the analogue
|
|
43
|
+
* of identityUpdates, but about someone/something else). `keid` is the referent from the
|
|
44
|
+
* known-entity dossier / "## People You Know" context. `name` is a learned identifying
|
|
45
|
+
* name; `learned` are facts (→ keid-tagged social beliefs, so they ride the memory
|
|
46
|
+
* pipeline); `feeling` is a felt valence toward them (a bounded nudge).
|
|
47
|
+
*/
|
|
48
|
+
knownEntityUpdates?: Array<{
|
|
49
|
+
keid: string
|
|
50
|
+
name?: string
|
|
51
|
+
learned?: string[]
|
|
52
|
+
feeling?: number
|
|
53
|
+
}>
|
|
54
|
+
newGoals?: Array<{
|
|
55
|
+
description: string
|
|
56
|
+
priority: number
|
|
57
|
+
tags: string[]
|
|
58
|
+
completionType: string
|
|
59
|
+
completionCondition?: string
|
|
60
|
+
}>
|
|
61
|
+
goalsToAbandon?: Array<{ goalId: string; reason: string }>
|
|
62
|
+
goalsToReprioritize?: Array<{ goalId: string; newPriority: number; reason: string }>
|
|
63
|
+
selfObservations?: string[]
|
|
64
|
+
/**
|
|
65
|
+
* Plain-text reply from a conversation facet — populated by parseResponse()
|
|
66
|
+
* from the [REPLY_TEXT]...[/REPLY_TEXT] block.
|
|
67
|
+
* Only present in facet mode (AuditionEngine). Undefined for master cycles.
|
|
68
|
+
* Paragraphs (double-newline separated) map to separate reply bubbles.
|
|
69
|
+
*/
|
|
70
|
+
replyText?: string
|
|
71
|
+
/**
|
|
72
|
+
* @deprecated Legacy JSON reply format — no longer emitted by conversation facets.
|
|
73
|
+
* Kept for backward compatibility with any tests/tooling that inspect parsed output.
|
|
74
|
+
*/
|
|
75
|
+
conversationReplies?: Array<{
|
|
76
|
+
targetEntityId: string
|
|
77
|
+
targetEntityName: string
|
|
78
|
+
messages: string[]
|
|
79
|
+
}>
|
|
80
|
+
/**
|
|
81
|
+
* System 2 only — the distinct approaches the master generated and weighed before
|
|
82
|
+
* committing, retained for explainability/auditability (and a future regret /
|
|
83
|
+
* counterfactual substrate). Populated on the deliberate (propose→evaluate) path;
|
|
84
|
+
* undefined for System 1 (the fast single-shot).
|
|
85
|
+
*/
|
|
86
|
+
consideredAlternatives?: string[]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── Ideation (System 2 propose pass) ─────────────────────────
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* One candidate approach from the deliberate path's ideation (propose) pass — a
|
|
93
|
+
* divergent option the master generated *before* deciding. The evaluate pass weighs
|
|
94
|
+
* these and commits; the chosen-against set is retained as `consideredAlternatives`.
|
|
95
|
+
*/
|
|
96
|
+
export interface IdeationCandidate {
|
|
97
|
+
/** Short handle for the option (e.g. "ask for clarification"). */
|
|
98
|
+
approach: string
|
|
99
|
+
/** One-line description of what this option concretely entails. */
|
|
100
|
+
description: string
|
|
101
|
+
/** Its main upside. */
|
|
102
|
+
upside: string
|
|
103
|
+
/** Its main risk or downside. */
|
|
104
|
+
risk: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Output of the ideation (propose) pass — a divergent candidate set, not a decision. */
|
|
108
|
+
export interface IdeationOutput {
|
|
109
|
+
candidates: IdeationCandidate[]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Plan output from the executive LLM.
|
|
114
|
+
*
|
|
115
|
+
* This is what the LLM produces in the [PLANS] tagged block.
|
|
116
|
+
* It includes lifecycle control fields (status, action, executionTier,
|
|
117
|
+
* expectedOutcome) that only the executive sets, plus the step structure
|
|
118
|
+
* that feeds into PlanningEngine's Plan type.
|
|
119
|
+
*/
|
|
120
|
+
export interface ExecutivePlanOutput {
|
|
121
|
+
/**
|
|
122
|
+
* Target an EXISTING plan for validate/execute/revise/cancel. Omit on a fresh
|
|
123
|
+
* `draft` to create a new plan. Enables managing multiple plans per goal (P4);
|
|
124
|
+
* when omitted, the op falls back to the goal's active plan.
|
|
125
|
+
*/
|
|
126
|
+
planId?: string
|
|
127
|
+
goalId: string
|
|
128
|
+
/** Lifecycle stage the executive is setting */
|
|
129
|
+
status: 'draft' | 'validated' | 'approved' | 'revised' | 'rejected'
|
|
130
|
+
/** What PlanningEngine should do with this plan */
|
|
131
|
+
action: 'draft' | 'validate' | 'execute' | 'revise' | 'cancel'
|
|
132
|
+
/** Concrete description of what successful completion looks like */
|
|
133
|
+
expectedOutcome?: string
|
|
134
|
+
/** The steps — mirrors PlanStep structure from PlanningEngine */
|
|
135
|
+
steps: Array<Pick<PlanStep, 'action' | 'description' | 'expectedOutcome' | 'estimatedDuration' | 'prerequisites'>>
|
|
136
|
+
estimatedCost: number
|
|
137
|
+
feasibility: number
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── Minimal output from LLM (before tagged-block parsing) ────
|
|
141
|
+
|
|
142
|
+
export interface ExecutiveOutputMinimal {
|
|
143
|
+
actions: Array<{ type: string; reasoning: string; expectedOutcome: string; target?: string }>
|
|
144
|
+
reasoning: string
|
|
145
|
+
confidence: number
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── Engine config ────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
export interface ExecutiveEngineConfig {
|
|
151
|
+
executiveInterval?: number
|
|
152
|
+
cooldownTicks?: number
|
|
153
|
+
bus?: CognitiveBus
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Context ──────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
export type ExecutiveAttentionType = 'available' | 'full'
|
|
159
|
+
export interface ExecutiveContext {
|
|
160
|
+
identity: {
|
|
161
|
+
/** Canonical persona name — from WillConfig.name (e.g. "Aria", "Guard-1"). */
|
|
162
|
+
name: string
|
|
163
|
+
prompt: string
|
|
164
|
+
values: string[]
|
|
165
|
+
traits: Record<string, number>
|
|
166
|
+
/**
|
|
167
|
+
* Per-trait self-knowledge (personal baseline + recent-shift direction) accumulated
|
|
168
|
+
* by the self-model, for graded-salience options B (relative to my own norm) and C
|
|
169
|
+
* ("rising/easing lately"). Absent until the self-model has evaluated at least once.
|
|
170
|
+
*/
|
|
171
|
+
traitStats?: Record<string, { mean: number; shiftDir: number; shiftTick: number }>
|
|
172
|
+
style: string
|
|
173
|
+
}
|
|
174
|
+
worldState: {
|
|
175
|
+
energyLevel: number
|
|
176
|
+
sleepPressure: number
|
|
177
|
+
stressLoad: number
|
|
178
|
+
circadianPhase: number
|
|
179
|
+
timeOfDay: number
|
|
180
|
+
/**
|
|
181
|
+
* Tonic threat level (0–1). Always present in the standing context so a
|
|
182
|
+
* *sustained* threat stays represented even after its events habituate out of
|
|
183
|
+
* the workspace — representation (this) is kept separate from attention
|
|
184
|
+
* (event salience). See reward/threat Option-B salience.
|
|
185
|
+
*/
|
|
186
|
+
threatLevel: number
|
|
187
|
+
}
|
|
188
|
+
affect: {
|
|
189
|
+
dominantEmotion: string
|
|
190
|
+
valence: number
|
|
191
|
+
arousal: number
|
|
192
|
+
dominance: number
|
|
193
|
+
blends: string[]
|
|
194
|
+
}
|
|
195
|
+
goals: Array<{
|
|
196
|
+
id: string
|
|
197
|
+
description: string
|
|
198
|
+
priority: number
|
|
199
|
+
progress: number
|
|
200
|
+
status: string
|
|
201
|
+
deadline?: number
|
|
202
|
+
lastActionAttemptTick?: number
|
|
203
|
+
lastActionType?: string
|
|
204
|
+
}>
|
|
205
|
+
/**
|
|
206
|
+
* Active/known plans, read from persisted `plan` entities — gives the executive
|
|
207
|
+
* execution awareness: which plans exist per goal, their status and step
|
|
208
|
+
* progress, so it can target a specific plan by id when managing several. (P4)
|
|
209
|
+
*/
|
|
210
|
+
plans: Array<{
|
|
211
|
+
id: string
|
|
212
|
+
goalId: string
|
|
213
|
+
status: string
|
|
214
|
+
executionTier: string
|
|
215
|
+
totalSteps: number
|
|
216
|
+
completedSteps: number
|
|
217
|
+
expectedOutcome: string
|
|
218
|
+
/** Causal link to the requester whose message spawned the plan (for scoping). */
|
|
219
|
+
requestingEntityId?: string
|
|
220
|
+
}>
|
|
221
|
+
/**
|
|
222
|
+
* Plan ids surfaced by the latest episodic recall (plan descriptors carry their
|
|
223
|
+
* planId) — drives recall-scoped plan awareness (AWARENESS Stage 2). Generalizes
|
|
224
|
+
* the scope filter from `requestingEntityId` to relevance.
|
|
225
|
+
*/
|
|
226
|
+
relevantPlanIds: string[]
|
|
227
|
+
percepts: Array<{
|
|
228
|
+
category: string
|
|
229
|
+
summary: string
|
|
230
|
+
salience: number
|
|
231
|
+
}>
|
|
232
|
+
workingMemory: Array<{
|
|
233
|
+
type: string
|
|
234
|
+
summary: string
|
|
235
|
+
activation: number
|
|
236
|
+
}>
|
|
237
|
+
memories: Array<{
|
|
238
|
+
content: string
|
|
239
|
+
relevance: number
|
|
240
|
+
emotionalContext: string
|
|
241
|
+
/** Simulation tick when this memory was consolidated. Used to render approximate age. */
|
|
242
|
+
tick?: number
|
|
243
|
+
}>
|
|
244
|
+
beliefs: Array<{
|
|
245
|
+
statement: string
|
|
246
|
+
category: string
|
|
247
|
+
confidence: number
|
|
248
|
+
}>
|
|
249
|
+
/** How many beliefs exist but were not included due to the relevance cap. */
|
|
250
|
+
beliefsOmitted: number
|
|
251
|
+
/**
|
|
252
|
+
* Recent action outcomes — shows the executive what it already tried and whether it
|
|
253
|
+
* landed. Built from `decision.record` entities with an `actionStatus` set.
|
|
254
|
+
* Surfaces the Act→Confirm→Perceive feedback loop into the executive's reasoning.
|
|
255
|
+
*/
|
|
256
|
+
recentActions: Array<{
|
|
257
|
+
/** Effector name that was invoked */
|
|
258
|
+
type: string
|
|
259
|
+
/** Lifecycle status set by ActionExecutor */
|
|
260
|
+
status: 'completed' | 'failed' | 'awaiting_host' | 'timed_out'
|
|
261
|
+
/** Tick the action was executed or dispatched */
|
|
262
|
+
tick: number
|
|
263
|
+
/** Short outcome description — truncated to 120 chars */
|
|
264
|
+
outcome: string
|
|
265
|
+
/** planId if this action came from a plan step */
|
|
266
|
+
planId?: string
|
|
267
|
+
}>
|
|
268
|
+
/** Behavioral disposition loaded from PMA at session start — stable per session. */
|
|
269
|
+
behavioralDisposition?: {
|
|
270
|
+
riskTolerance: number
|
|
271
|
+
explorationRate: number
|
|
272
|
+
impulsivity: number
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* How the Will has self-tuned its own faculties (the metacognition cycle's
|
|
276
|
+
* persona-prior), as first-person phrases — lets the deliberate self see its
|
|
277
|
+
* own accommodation. Omitted when no prior is active.
|
|
278
|
+
*/
|
|
279
|
+
selfTuning?: string[]
|
|
280
|
+
/**
|
|
281
|
+
* What the Will knows about the others it has encountered — the known-entity dossier
|
|
282
|
+
* view, surfaced for reasoning. Joins theory-of-mind (what they seem to want/feel),
|
|
283
|
+
* reputation (trust/cooperativeness/reliability) and attachment (closeness) per `keid`,
|
|
284
|
+
* sorted by interaction recency, capped. `name` may be absent — the Will can know
|
|
285
|
+
* *someone* without yet knowing their name (provisional identity). `kind` is `sentient`
|
|
286
|
+
* for everything modelled here today; `thing` arrives with the generalised dossier.
|
|
287
|
+
* Omitted when the Will knows no one.
|
|
288
|
+
*/
|
|
289
|
+
knownEntities?: Array<{
|
|
290
|
+
keid: string
|
|
291
|
+
kind: 'sentient' | 'thing'
|
|
292
|
+
name?: string
|
|
293
|
+
intention?: string
|
|
294
|
+
emotion?: string
|
|
295
|
+
trust?: number
|
|
296
|
+
cooperativeness?: number
|
|
297
|
+
closeness?: number
|
|
298
|
+
reliability?: number
|
|
299
|
+
confidence?: number
|
|
300
|
+
}>
|
|
301
|
+
/**
|
|
302
|
+
* What the Will is currently focused on (task.switcher) and how committed — surfaces
|
|
303
|
+
* task-persistence so the deliberate self weighs the cost of switching away. The
|
|
304
|
+
* `switchCost` (= effective `baseSwitchCost`, conscientiousness-developable, #28) scales
|
|
305
|
+
* how strong the pull to stay is. Omitted when nothing is in focus.
|
|
306
|
+
*/
|
|
307
|
+
currentFocus?: {
|
|
308
|
+
goalId: string
|
|
309
|
+
goalDescription?: string
|
|
310
|
+
focusTicks: number
|
|
311
|
+
switchCost: number
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ── Pending message ──────────────────────────────────────────
|
|
316
|
+
|
|
317
|
+
export interface PendingMessage {
|
|
318
|
+
id: string
|
|
319
|
+
content: string
|
|
320
|
+
sender: string
|
|
321
|
+
senderId: string
|
|
322
|
+
tick: number
|
|
323
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/exteroception.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Exteroception — processes external world events into structured percepts.
|
|
7
|
+
*
|
|
8
|
+
* Scans the event bus and entity space for:
|
|
9
|
+
* - New entities entering the world
|
|
10
|
+
* - Changes to existing entities
|
|
11
|
+
* - Explicit events (messages, notifications, environmental changes)
|
|
12
|
+
* - Other agents' observable actions
|
|
13
|
+
*
|
|
14
|
+
* Each percept is an entity with salience tagging, enabling downstream
|
|
15
|
+
* engines (Attention, Affective, Memory) to prioritize processing.
|
|
16
|
+
*
|
|
17
|
+
* Part of Shard 0 (Perceptual Layer) — runs every tick, synchronous.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type {
|
|
21
|
+
Duration,
|
|
22
|
+
Tick,
|
|
23
|
+
Timestamp,
|
|
24
|
+
SimulationContext,
|
|
25
|
+
ReadonlySimulationState,
|
|
26
|
+
StateCommands,
|
|
27
|
+
SimulationEvent,
|
|
28
|
+
SimulationEntity,
|
|
29
|
+
} from '#core/types'
|
|
30
|
+
import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
|
|
31
|
+
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
32
|
+
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
33
|
+
import { GenerativeModel } from '#cognition/generative.model'
|
|
34
|
+
|
|
35
|
+
export interface ExteroceptionConfig {
|
|
36
|
+
/** Maximum percepts to produce per tick */
|
|
37
|
+
maxPerceptsPerTick?: number
|
|
38
|
+
/** Default salience for unmarked percepts */
|
|
39
|
+
defaultSalience?: number
|
|
40
|
+
/** Whether to emit percept events */
|
|
41
|
+
emitPerceptEvents?: boolean
|
|
42
|
+
/** Entity types to always treat as high-salience */
|
|
43
|
+
highPriorityTypes?: string[]
|
|
44
|
+
bus?: CognitiveBus
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface RawPercept {
|
|
48
|
+
entityId: string
|
|
49
|
+
changeType: 'appeared' | 'modified' | 'removed'
|
|
50
|
+
salience: number
|
|
51
|
+
category: string
|
|
52
|
+
summary: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Skip internal entities — they're not external percepts.
|
|
56
|
+
// Percepts about percepts create a feedback loop that floods
|
|
57
|
+
// working memory and episodic storage with noise.
|
|
58
|
+
const internalTypes = new Set([
|
|
59
|
+
'percept', 'percept.social', 'working_memory.item',
|
|
60
|
+
'interoception', 'attention.focus', 'decision.record',
|
|
61
|
+
'task.focus', 'self_observation',
|
|
62
|
+
'goal', 'belief', 'plan', 'narrative_chapter',
|
|
63
|
+
'introspection', 'self_narrative', 'cognitive_bias',
|
|
64
|
+
'effector.created', 'empathic_state', 'attachment.bond',
|
|
65
|
+
'theory_of_mind', 'reputation', 'episodic_memory',
|
|
66
|
+
// Internal state entities written by our own engines — not external events
|
|
67
|
+
'affect.blends', 'executive.summary',
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
export class Exteroception implements SimulationEngine, CognitiveEngine {
|
|
71
|
+
readonly name = 'exteroception'
|
|
72
|
+
|
|
73
|
+
private _maxPerceptsPerTick: number
|
|
74
|
+
private _defaultSalience: number
|
|
75
|
+
private _emitPerceptEvents: boolean
|
|
76
|
+
private _highPriorityTypes: Set<string>
|
|
77
|
+
private _previousEntityVersions = new Map<string, number>() // entityId → updatedAt
|
|
78
|
+
|
|
79
|
+
private _bus: CognitiveBus | null = null
|
|
80
|
+
|
|
81
|
+
private readonly _model = new GenerativeModel()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
constructor( config: ExteroceptionConfig = {} ){
|
|
85
|
+
this._bus = config.bus ?? null
|
|
86
|
+
this._maxPerceptsPerTick = config.maxPerceptsPerTick ?? 50
|
|
87
|
+
this._defaultSalience = config.defaultSalience ?? 0.3
|
|
88
|
+
this._emitPerceptEvents = config.emitPerceptEvents ?? true
|
|
89
|
+
this._highPriorityTypes = new Set( config.highPriorityTypes ?? [
|
|
90
|
+
'message', 'notification', 'alert', 'threat', 'goal',
|
|
91
|
+
])
|
|
92
|
+
}
|
|
93
|
+
attachBus( bus: CognitiveBus ): void { this._bus = bus }
|
|
94
|
+
|
|
95
|
+
// ── Engine interface ─────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
subscribes(): string[] { return ['executive.prediction.formed'] }
|
|
98
|
+
publishes(): CognitiveEventSchema[] {
|
|
99
|
+
return [{ type: 'percept.category.updated', version: 1, validate: () => null }]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
|
|
103
|
+
this._model.observe( e.type, e.salience )
|
|
104
|
+
if( e.type === 'executive.prediction.formed' ){
|
|
105
|
+
const p = e.payload as { predictedDomains: string[]; confidence: number }
|
|
106
|
+
if( p.predictedDomains.includes('perception') )
|
|
107
|
+
this._model.setPrecision( 'percept.rate', 1.0 + p.confidence * 0.5 )
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
snapshot(): Record<string, unknown> { return {} }
|
|
112
|
+
|
|
113
|
+
async react(
|
|
114
|
+
_delta: Duration,
|
|
115
|
+
tick: Tick,
|
|
116
|
+
state: ReadonlySimulationState,
|
|
117
|
+
context: SimulationContext
|
|
118
|
+
): Promise<EngineResult> {
|
|
119
|
+
const
|
|
120
|
+
events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
|
|
121
|
+
commands: StateCommands = { set: [], delete: [], metrics: [] }
|
|
122
|
+
|
|
123
|
+
const rawPercepts = this._scanWorld( state )
|
|
124
|
+
|
|
125
|
+
// Cap percepts per tick
|
|
126
|
+
const capped = rawPercepts.slice( 0, this._maxPerceptsPerTick )
|
|
127
|
+
|
|
128
|
+
// Convert raw percepts to entities
|
|
129
|
+
for( let i = 0; i < capped.length; i++ ){
|
|
130
|
+
const rp = capped[i]!
|
|
131
|
+
|
|
132
|
+
const perceptEntity = {
|
|
133
|
+
id: `percept-${tick}-${i}`,
|
|
134
|
+
type: 'percept',
|
|
135
|
+
metadata: {
|
|
136
|
+
entityId: rp.entityId,
|
|
137
|
+
changeType: rp.changeType,
|
|
138
|
+
salience: rp.salience,
|
|
139
|
+
category: rp.category,
|
|
140
|
+
summary: rp.summary,
|
|
141
|
+
tick,
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
commands.set!.push( perceptEntity )
|
|
146
|
+
|
|
147
|
+
// Emit percept event for downstream engines
|
|
148
|
+
if( this._emitPerceptEvents )
|
|
149
|
+
events.push({
|
|
150
|
+
type: `percept.${rp.changeType}.${rp.category}`,
|
|
151
|
+
source: this.name,
|
|
152
|
+
payload: {
|
|
153
|
+
entityId: rp.entityId,
|
|
154
|
+
salience: rp.salience,
|
|
155
|
+
category: rp.category,
|
|
156
|
+
summary: rp.summary,
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Clean up old percepts from previous ticks (keep last 2 ticks of percepts)
|
|
162
|
+
commands.delete = this._collectStalePerceptIds( state, tick )
|
|
163
|
+
|
|
164
|
+
// Aggregate metrics
|
|
165
|
+
commands.metrics!.push(
|
|
166
|
+
[ 'perception.percepts_this_tick', capped.length ],
|
|
167
|
+
[ 'perception.total_entities_observed', state.entities.size ],
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
// Phase C + F: publish cognitive event — gated by prediction error
|
|
172
|
+
const _bus = this._bus
|
|
173
|
+
if( _bus && capped.length > 0 ){
|
|
174
|
+
const predErr = this._model.observe( 'percept.rate', capped.length )
|
|
175
|
+
if( !predErr.gated )
|
|
176
|
+
_bus.publish({ type: 'percept.batch.ingested', version: 1, sourceEngine: this.name, salience: Math.max( 0.2, predErr.salience ), payload: { count: capped.length } })
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// percept.category.updated — one event per distinct category so subscribers
|
|
180
|
+
// (aesthetic.evaluator etc.) get a structured signal without scanning percepts
|
|
181
|
+
if( _bus && capped.length > 0 ){
|
|
182
|
+
const countByCategory = new Map<string, number>()
|
|
183
|
+
for( const rp of capped )
|
|
184
|
+
countByCategory.set( rp.category, ( countByCategory.get( rp.category ) ?? 0 ) + 1 )
|
|
185
|
+
for( const [ category, count ] of countByCategory )
|
|
186
|
+
_bus.publish({ type: 'percept.category.updated', version: 1, sourceEngine: this.name, salience: Math.min( 1, count * 0.15 + 0.2 ), payload: { category, count } })
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { events: events.length > 0 ? events : undefined, commands }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── Internal ─────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Scan the world for perceptible changes.
|
|
196
|
+
* Compares current entity state against previous versions.
|
|
197
|
+
*/
|
|
198
|
+
// In _scanWorld(), replace the entity loop with this:
|
|
199
|
+
|
|
200
|
+
private _scanWorld( state: ReadonlySimulationState ): RawPercept[] {
|
|
201
|
+
const percepts: RawPercept[] = []
|
|
202
|
+
const currentIds = new Set<string>()
|
|
203
|
+
|
|
204
|
+
for( const [ id, entity ] of state.entities ){
|
|
205
|
+
currentIds.add( id )
|
|
206
|
+
|
|
207
|
+
if( internalTypes.has( entity.type ) ){
|
|
208
|
+
// Still track the version so we don't get "appeared" events
|
|
209
|
+
// when these internal entities are first created
|
|
210
|
+
this._previousEntityVersions.set( id, entity.updatedAt )
|
|
211
|
+
continue
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const previousVersion = this._previousEntityVersions.get( id )
|
|
215
|
+
|
|
216
|
+
if( previousVersion === undefined ){
|
|
217
|
+
percepts.push({
|
|
218
|
+
entityId: id,
|
|
219
|
+
changeType: 'appeared',
|
|
220
|
+
salience: this._computeSalience( entity, 'appeared', state.time ),
|
|
221
|
+
category: entity.type,
|
|
222
|
+
summary: this._summarizeEntity( entity, 'appeared'),
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
else if( entity.updatedAt > previousVersion ){
|
|
226
|
+
percepts.push({
|
|
227
|
+
entityId: id,
|
|
228
|
+
changeType: 'modified',
|
|
229
|
+
salience: this._computeSalience( entity, 'modified', state.time ),
|
|
230
|
+
category: entity.type,
|
|
231
|
+
summary: this._summarizeEntity( entity, 'modified'),
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
this._previousEntityVersions.set( id, entity.updatedAt )
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Detect removed entities (not internal types)
|
|
239
|
+
for( const [ id ] of this._previousEntityVersions ){
|
|
240
|
+
if( !currentIds.has( id ) ){
|
|
241
|
+
// Only report removal of meaningful entities
|
|
242
|
+
// We can't check the type here since the entity is gone,
|
|
243
|
+
// but we can infer from the ID prefix
|
|
244
|
+
if( !id.startsWith('percept-')
|
|
245
|
+
&& !id.startsWith('wm-')
|
|
246
|
+
&& !id.startsWith('attention-')
|
|
247
|
+
&& !id.startsWith('decision-')
|
|
248
|
+
&& !id.startsWith('interoception-')
|
|
249
|
+
&& !id.startsWith('task-')
|
|
250
|
+
&& !id.startsWith('self-obs-') ){
|
|
251
|
+
percepts.push({
|
|
252
|
+
entityId: id,
|
|
253
|
+
changeType: 'removed',
|
|
254
|
+
salience: 0.4,
|
|
255
|
+
category: 'removed',
|
|
256
|
+
summary: `Entity removed: ${id}`,
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
this._previousEntityVersions.delete( id )
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
percepts.sort( ( a, b ) => b.salience - a.salience )
|
|
264
|
+
return percepts
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Generate a meaningful summary for an entity.
|
|
269
|
+
* Instead of "New percept: percept-54-0", produce something useful.
|
|
270
|
+
*/
|
|
271
|
+
private _summarizeEntity(
|
|
272
|
+
entity: Readonly<SimulationEntity>,
|
|
273
|
+
changeType: string
|
|
274
|
+
): string {
|
|
275
|
+
const name = entity.metadata?.name as string | undefined
|
|
276
|
+
const description = entity.metadata?.description as string | undefined
|
|
277
|
+
|
|
278
|
+
if( name ){
|
|
279
|
+
return changeType === 'appeared'
|
|
280
|
+
? `${name} appears` : `${name} changed`
|
|
281
|
+
}
|
|
282
|
+
if( description ){
|
|
283
|
+
return description.slice( 0, 100 )
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return `New ${entity.type}: ${entity.id.slice(0, 30)}`
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Compute salience of a percept based on entity characteristics.
|
|
291
|
+
*/
|
|
292
|
+
private _computeSalience(
|
|
293
|
+
entity: Readonly<SimulationEntity>,
|
|
294
|
+
_changeType: string,
|
|
295
|
+
now: Timestamp
|
|
296
|
+
): number {
|
|
297
|
+
let salience = this._defaultSalience
|
|
298
|
+
|
|
299
|
+
// High-priority types get baseline boost
|
|
300
|
+
if( this._highPriorityTypes.has( entity.type ) )
|
|
301
|
+
salience += 0.4
|
|
302
|
+
|
|
303
|
+
// Entity metadata can specify explicit salience
|
|
304
|
+
if( typeof entity.metadata?.salience === 'number')
|
|
305
|
+
salience = entity.metadata.salience
|
|
306
|
+
|
|
307
|
+
// Urgency metadata boosts salience
|
|
308
|
+
if( typeof entity.metadata?.urgency === 'number')
|
|
309
|
+
salience += entity.metadata.urgency * 0.3
|
|
310
|
+
|
|
311
|
+
// Recency boost — entities with recent updatedAt are more salient.
|
|
312
|
+
// Both sides are sim-time ms (updatedAt is stamped by StateManager from the
|
|
313
|
+
// sim clock), so recency is measured against sim-time, never wall-clock (R2).
|
|
314
|
+
const ageSeconds = ( now - entity.updatedAt ) / 1000
|
|
315
|
+
if( ageSeconds < 10 )
|
|
316
|
+
salience += 0.2
|
|
317
|
+
else if( ageSeconds < 60 )
|
|
318
|
+
salience += 0.1
|
|
319
|
+
|
|
320
|
+
return Math.min( 1, Math.max( 0, salience ) )
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Collect IDs of stale percept entities to clean up.
|
|
325
|
+
*/
|
|
326
|
+
private _collectStalePerceptIds( state: ReadonlySimulationState, currentTick: Tick ): string[] {
|
|
327
|
+
const stale: string[] = []
|
|
328
|
+
|
|
329
|
+
for( const [ id, entity ] of state.entities ){
|
|
330
|
+
if( entity.type === 'percept' && typeof entity.metadata?.tick === 'number'){
|
|
331
|
+
if( currentTick - entity.metadata.tick > 2 )
|
|
332
|
+
stale.push( id )
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return stale
|
|
337
|
+
}
|
|
338
|
+
}
|