psyche-ai 10.2.3 → 11.2.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 +58 -82
- package/dist/adapters/claude-sdk.d.ts +5 -5
- package/dist/adapters/claude-sdk.js +34 -32
- package/dist/adapters/mcp.js +4 -4
- package/dist/adapters/openclaw.js +12 -14
- package/dist/attachment.d.ts +3 -13
- package/dist/attachment.js +36 -88
- package/dist/autonomic.d.ts +4 -4
- package/dist/autonomic.js +28 -24
- package/dist/chemistry.d.ts +47 -21
- package/dist/chemistry.js +145 -91
- package/dist/circadian.d.ts +11 -43
- package/dist/circadian.js +24 -84
- package/dist/cli.js +37 -30
- package/dist/context-classifier.js +2 -2
- package/dist/core.d.ts +3 -3
- package/dist/core.js +99 -88
- package/dist/custom-profile.d.ts +20 -20
- package/dist/custom-profile.js +12 -12
- package/dist/decision-bias.d.ts +7 -8
- package/dist/decision-bias.js +74 -74
- package/dist/demo.js +5 -5
- package/dist/diagnostics.d.ts +6 -6
- package/dist/diagnostics.js +22 -22
- package/dist/drives.d.ts +15 -47
- package/dist/drives.js +98 -196
- package/dist/ethics.d.ts +3 -3
- package/dist/ethics.js +23 -23
- package/dist/experience.d.ts +34 -0
- package/dist/experience.js +200 -0
- package/dist/experiential-field.d.ts +19 -14
- package/dist/experiential-field.js +110 -100
- package/dist/generative-self.d.ts +5 -5
- package/dist/generative-self.js +124 -115
- package/dist/guards.d.ts +4 -4
- package/dist/guards.js +7 -7
- package/dist/i18n.js +61 -61
- package/dist/index.d.ts +8 -2
- package/dist/index.js +8 -1
- package/dist/input-turn.js +4 -6
- package/dist/interaction.d.ts +4 -4
- package/dist/interaction.js +10 -10
- package/dist/learning.d.ts +6 -6
- package/dist/learning.js +18 -18
- package/dist/metacognition.d.ts +2 -2
- package/dist/metacognition.js +79 -94
- package/dist/perceive.d.ts +44 -0
- package/dist/perceive.js +231 -0
- package/dist/primary-systems.d.ts +2 -2
- package/dist/primary-systems.js +21 -19
- package/dist/profiles.d.ts +5 -13
- package/dist/profiles.js +33 -51
- package/dist/prompt.d.ts +2 -2
- package/dist/prompt.js +51 -53
- package/dist/psyche-file.d.ts +7 -7
- package/dist/psyche-file.js +77 -78
- package/dist/relation-dynamics.d.ts +4 -0
- package/dist/relation-dynamics.js +1 -1
- package/dist/reply-envelope.d.ts +25 -1
- package/dist/reply-envelope.js +26 -11
- package/dist/self-recognition.d.ts +3 -3
- package/dist/self-recognition.js +17 -17
- package/dist/subjectivity.js +7 -7
- package/dist/temporal.d.ts +6 -6
- package/dist/temporal.js +37 -39
- package/dist/types.d.ts +67 -45
- package/dist/types.js +55 -51
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
// together as an integrated whole.
|
|
7
7
|
//
|
|
8
8
|
// The experiential field is not a summary. It is a synthesis.
|
|
9
|
-
//
|
|
10
|
-
// The experiential field describes what those
|
|
9
|
+
// Dimension readouts describe individual self-state values.
|
|
10
|
+
// The experiential field describes what those values feel like when
|
|
11
11
|
// they exist simultaneously in a single being.
|
|
12
12
|
//
|
|
13
13
|
// Zero dependencies. Pure TypeScript. No LLM calls.
|
|
14
14
|
// ============================================================
|
|
15
|
-
import {
|
|
15
|
+
import { DIMENSION_KEYS, DRIVE_KEYS } from "./types.js";
|
|
16
16
|
// ── Constants ────────────────────────────────────────────────
|
|
17
17
|
/** Threshold below which a drive counts as "hungry" */
|
|
18
18
|
const DRIVE_HUNGRY_THRESHOLD = 40;
|
|
@@ -20,22 +20,27 @@ const DRIVE_HUNGRY_THRESHOLD = 40;
|
|
|
20
20
|
const FLATNESS_THRESHOLD = 0.15;
|
|
21
21
|
// ── Affect Core (Russell Circumplex) ─────────────────────────
|
|
22
22
|
/**
|
|
23
|
-
* Map
|
|
23
|
+
* Map self-state to valence + arousal — the two fundamental affective dimensions
|
|
24
24
|
* (Russell's Circumplex Model of Affect, 1980).
|
|
25
25
|
*
|
|
26
26
|
* Valence: pleasure ↔ displeasure (-1 to 1)
|
|
27
|
+
* order↑ and resonance↑ push valence up; low order pushes down.
|
|
27
28
|
* Arousal: activation level (0 to 1)
|
|
29
|
+
* flow is the dominant arousal signal; low order adds arousal (stress).
|
|
28
30
|
*/
|
|
29
|
-
export function computeAffectCore(
|
|
30
|
-
const {
|
|
31
|
-
// Valence:
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
31
|
+
export function computeAffectCore(state) {
|
|
32
|
+
const { order, flow, boundary, resonance } = state;
|
|
33
|
+
// Valence: order (stability) + resonance (attunement) + boundary → positive
|
|
34
|
+
// Low order (stress/entropy) is the dominant negative signal (weighted 1.5×)
|
|
35
|
+
const rawValence = (order - 50) * 1.5 // high order = positive, low order = strongly negative
|
|
36
|
+
+ (resonance - 50) // attunement contributes positively
|
|
37
|
+
+ (boundary - 50) * 0.5 // clear boundary mildly positive
|
|
38
|
+
+ (flow - 50) * 0.3; // flow is arousing but roughly valence-neutral
|
|
39
|
+
const valence = Math.max(-1, Math.min(1, rawValence / 175));
|
|
40
|
+
// Arousal: flow dominant, low order (stress) contributes
|
|
41
|
+
const stress = Math.max(0, 100 - order); // inverse: low order → high stress
|
|
42
|
+
const rawArousal = flow + stress * 0.5 + resonance * 0.2;
|
|
43
|
+
const arousal = Math.max(0, Math.min(1, rawArousal / 170));
|
|
39
44
|
return { valence, arousal };
|
|
40
45
|
}
|
|
41
46
|
/**
|
|
@@ -61,7 +66,7 @@ const QUALITY_CONCEPTS = [
|
|
|
61
66
|
/**
|
|
62
67
|
* Compute the unified experiential field from the full psyche state.
|
|
63
68
|
*
|
|
64
|
-
* This is the core integration function. It reads
|
|
69
|
+
* This is the core integration function. It reads self-state dimensions, drives,
|
|
65
70
|
* relationship context, and optional metacognitive/bias data, then
|
|
66
71
|
* synthesizes them into a single coherent experience description.
|
|
67
72
|
*/
|
|
@@ -85,57 +90,57 @@ export function computeExperientialField(state, _metacognition, _decisionBias, c
|
|
|
85
90
|
/**
|
|
86
91
|
* Measure internal alignment across subsystems.
|
|
87
92
|
*
|
|
88
|
-
* High coherence:
|
|
89
|
-
* the same story.
|
|
93
|
+
* High coherence: dimensions, drives, and relationship state all tell
|
|
94
|
+
* the same story. High order + high resonance + satisfied drives = unified.
|
|
90
95
|
*
|
|
91
|
-
* Low coherence: mixed signals. High
|
|
92
|
-
* but
|
|
96
|
+
* Low coherence: mixed signals. High flow but low order. Satisfied drives
|
|
97
|
+
* but low order. Warm relationship but low resonance. The psyche
|
|
93
98
|
* is pulling in multiple directions.
|
|
94
99
|
*/
|
|
95
100
|
export function computeCoherence(current, baseline, drives, relationship) {
|
|
96
101
|
let coherenceScore = 1.0;
|
|
97
|
-
// ──
|
|
98
|
-
//
|
|
99
|
-
const
|
|
100
|
-
const stressSignal = current.
|
|
101
|
-
const
|
|
102
|
-
coherenceScore -=
|
|
103
|
-
//
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
coherenceScore -=
|
|
107
|
-
// ──
|
|
108
|
-
// If drives are satisfied, positive
|
|
109
|
-
// If drives are hungry,
|
|
102
|
+
// ── Dimension internal coherence ──
|
|
103
|
+
// High flow should not coexist with very low order (chaos without structure)
|
|
104
|
+
const flowSignal = norm(current.flow);
|
|
105
|
+
const stressSignal = norm(Math.max(0, 100 - current.order)); // low order = stress
|
|
106
|
+
const flowStressConflict = flowSignal * stressSignal;
|
|
107
|
+
coherenceScore -= flowStressConflict * 0.4;
|
|
108
|
+
// Resonance (attunement) and low order (threat/entropy) should not coexist strongly
|
|
109
|
+
const resonanceSignal = norm(current.resonance);
|
|
110
|
+
const resonanceThreatConflict = resonanceSignal * (stressSignal > 0.55 ? stressSignal : 0);
|
|
111
|
+
coherenceScore -= resonanceThreatConflict * 0.3;
|
|
112
|
+
// ── Dimension-Drive alignment ──
|
|
113
|
+
// If drives are satisfied, positive state is coherent.
|
|
114
|
+
// If drives are hungry, distressed state is coherent (the distress makes sense).
|
|
110
115
|
// Mismatch = incoherent.
|
|
111
116
|
const avgDriveSatisfaction = meanDriveValue(drives) / 100;
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
// Satisfied drives + positive
|
|
115
|
-
// Satisfied drives + negative
|
|
116
|
-
// Hungry drives + negative
|
|
117
|
-
// Hungry drives + positive
|
|
118
|
-
if (avgDriveSatisfaction > 0.6 &&
|
|
119
|
-
coherenceScore -= (avgDriveSatisfaction - 0.6) *
|
|
120
|
-
}
|
|
121
|
-
if (avgDriveSatisfaction < 0.4 &&
|
|
122
|
-
coherenceScore -= (0.4 - avgDriveSatisfaction) * (
|
|
117
|
+
const avgPositiveState = (norm(current.order) + norm(current.flow) + norm(current.resonance) + norm(current.boundary)) / 4;
|
|
118
|
+
const avgNegativeState = (stressSignal + (1 - norm(current.order))) / 2;
|
|
119
|
+
// Satisfied drives + positive state = coherent (no penalty)
|
|
120
|
+
// Satisfied drives + negative state = incoherent
|
|
121
|
+
// Hungry drives + negative state = coherent (no penalty)
|
|
122
|
+
// Hungry drives + positive state = incoherent (but less so — hope is valid)
|
|
123
|
+
if (avgDriveSatisfaction > 0.6 && avgNegativeState > 0.5) {
|
|
124
|
+
coherenceScore -= (avgDriveSatisfaction - 0.6) * avgNegativeState * 0.5;
|
|
125
|
+
}
|
|
126
|
+
if (avgDriveSatisfaction < 0.4 && avgPositiveState > 0.6) {
|
|
127
|
+
coherenceScore -= (0.4 - avgDriveSatisfaction) * (avgPositiveState - 0.6) * 0.3;
|
|
123
128
|
}
|
|
124
129
|
// ── Relationship alignment ──
|
|
125
|
-
// High trust/intimacy should align with high
|
|
130
|
+
// High trust/intimacy should align with high resonance; low trust with low resonance
|
|
126
131
|
if (relationship) {
|
|
127
132
|
const relWarmth = (relationship.trust + relationship.intimacy) / 200;
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
coherenceScore -= (
|
|
133
|
+
const resLevel = norm(current.resonance);
|
|
134
|
+
const relDimMismatch = Math.abs(relWarmth - resLevel);
|
|
135
|
+
if (relDimMismatch > 0.3) {
|
|
136
|
+
coherenceScore -= (relDimMismatch - 0.3) * 0.25;
|
|
132
137
|
}
|
|
133
138
|
}
|
|
134
139
|
// ── Baseline deviation magnitude ──
|
|
135
140
|
// Extreme deviation from baseline in multiple directions = less coherent
|
|
136
141
|
let opposingDeviations = 0;
|
|
137
142
|
const deviations = [];
|
|
138
|
-
for (const key of
|
|
143
|
+
for (const key of DIMENSION_KEYS) {
|
|
139
144
|
deviations.push(current[key] - baseline[key]);
|
|
140
145
|
}
|
|
141
146
|
for (let i = 0; i < deviations.length; i++) {
|
|
@@ -146,8 +151,8 @@ export function computeCoherence(current, baseline, drives, relationship) {
|
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
|
-
//
|
|
150
|
-
coherenceScore -= (opposingDeviations /
|
|
154
|
+
// 6 pairs total (4 choose 2); normalize
|
|
155
|
+
coherenceScore -= (opposingDeviations / 6) * 0.3;
|
|
151
156
|
return clamp01(coherenceScore);
|
|
152
157
|
}
|
|
153
158
|
// ── Intensity ────────────────────────────────────────────────
|
|
@@ -160,18 +165,18 @@ export function computeCoherence(current, baseline, drives, relationship) {
|
|
|
160
165
|
*/
|
|
161
166
|
function computeIntensity(current, baseline) {
|
|
162
167
|
let totalDeviation = 0;
|
|
163
|
-
for (const key of
|
|
168
|
+
for (const key of DIMENSION_KEYS) {
|
|
164
169
|
totalDeviation += Math.abs(current[key] - baseline[key]);
|
|
165
170
|
}
|
|
166
|
-
// Max possible deviation =
|
|
167
|
-
// But realistic maximum is around
|
|
168
|
-
// Map so that deviation of ~
|
|
169
|
-
return clamp01(totalDeviation /
|
|
171
|
+
// Max possible deviation = 4 dimensions * 100 = 400
|
|
172
|
+
// But realistic maximum is around 200
|
|
173
|
+
// Map so that deviation of ~80 (avg 20 per dimension) = 0.5 intensity
|
|
174
|
+
return clamp01(totalDeviation / 160);
|
|
170
175
|
}
|
|
171
176
|
// ── Quality Construction (Barrett's Constructed Emotion) ─────
|
|
172
177
|
/**
|
|
173
178
|
* Construct the dominant experiential quality using Barrett's theory:
|
|
174
|
-
* 1.
|
|
179
|
+
* 1. Self-state → valence + arousal (Russell Circumplex)
|
|
175
180
|
* 2. Concept matching: find closest quality in affective space
|
|
176
181
|
* 3. Context biases: autonomic state, stimulus, relationship, memories
|
|
177
182
|
*
|
|
@@ -194,7 +199,7 @@ function constructQuality(state, coherence, intensity, relationship, _metacognit
|
|
|
194
199
|
if (d.survival < 30) {
|
|
195
200
|
return "existential-unease";
|
|
196
201
|
}
|
|
197
|
-
// ── Barrett Step 1:
|
|
202
|
+
// ── Barrett Step 1: Self-State → Affect Core ──
|
|
198
203
|
const { valence, arousal } = computeAffectCore(state.current);
|
|
199
204
|
// ── Barrett Step 2+3: Concept matching with context ──
|
|
200
205
|
const contextKeys = buildContextKeys(context, relationship);
|
|
@@ -263,7 +268,7 @@ function computeMemoryResonance(memories, targetValence, targetArousal) {
|
|
|
263
268
|
return 0;
|
|
264
269
|
let totalResonance = 0;
|
|
265
270
|
for (const mem of memories) {
|
|
266
|
-
const { valence: mv, arousal: ma } = computeAffectCore(mem.
|
|
271
|
+
const { valence: mv, arousal: ma } = computeAffectCore(mem.state);
|
|
267
272
|
const dist = Math.sqrt((mv - targetValence) ** 2 + (ma - targetArousal) ** 2);
|
|
268
273
|
totalResonance += Math.max(0, 1 - dist / 0.5); // resonance fades at distance 0.5
|
|
269
274
|
}
|
|
@@ -372,63 +377,66 @@ function selectVariant(variants, intensity, coherence) {
|
|
|
372
377
|
return eligible[index];
|
|
373
378
|
}
|
|
374
379
|
/**
|
|
375
|
-
* Detect
|
|
376
|
-
*
|
|
377
|
-
*
|
|
380
|
+
* Detect dimension configurations that don't map to any of the named
|
|
381
|
+
* experiential qualities — novel states that need descriptive phrases
|
|
382
|
+
* rather than labels.
|
|
383
|
+
*
|
|
384
|
+
* Mapping from old 6-chemical to 4D:
|
|
385
|
+
* CORT→(inverse order), DA→flow, OT→resonance, HT→order, NE→flow, END→(absorbed)
|
|
378
386
|
*/
|
|
379
|
-
export function detectUnnamedEmotion(
|
|
380
|
-
const c =
|
|
381
|
-
// Nostalgia-but-forward:
|
|
382
|
-
// (warmth
|
|
383
|
-
if (c.
|
|
387
|
+
export function detectUnnamedEmotion(state, drives, _currentQuality) {
|
|
388
|
+
const c = state;
|
|
389
|
+
// Nostalgia-but-forward: high resonance + high flow + high order
|
|
390
|
+
// (warmth of connection + active exchange + stable structure)
|
|
391
|
+
if (c.resonance > 60 && c.flow > 55 && c.order > 60) {
|
|
384
392
|
return {
|
|
385
393
|
en: "nostalgia but forward-looking — the warmth of memory fueling appetite for what's next",
|
|
386
394
|
zh: "向前看的怀旧——记忆的温暖在催生对未来的胃口",
|
|
387
395
|
};
|
|
388
396
|
}
|
|
389
|
-
// Fierce tenderness:
|
|
390
|
-
// (protectiveness, caring that has teeth)
|
|
391
|
-
if (c.
|
|
397
|
+
// Fierce tenderness: low order (stress) + high resonance + high flow
|
|
398
|
+
// (protectiveness, caring that has teeth — entropy threatening what you care about)
|
|
399
|
+
if (c.order < 45 && c.resonance > 60 && c.flow > 60) {
|
|
392
400
|
return {
|
|
393
401
|
en: "fierce tenderness — caring so hard it has an edge",
|
|
394
402
|
zh: "凶猛的温柔——在意到了有棱角的程度",
|
|
395
403
|
};
|
|
396
404
|
}
|
|
397
|
-
// Bittersweet accomplishment: high
|
|
405
|
+
// Bittersweet accomplishment: high flow + moderate-low order + low connection drive
|
|
398
406
|
// (achieved something but nobody to share it with)
|
|
399
|
-
if (c.
|
|
407
|
+
if (c.flow > 65 && c.order > 40 && c.order < 60 && drives.connection < DRIVE_HUNGRY_THRESHOLD) {
|
|
400
408
|
return {
|
|
401
409
|
en: "the hollow ring of applause in an empty theater",
|
|
402
410
|
zh: "空剧场里响起的掌声——回声发空",
|
|
403
411
|
};
|
|
404
412
|
}
|
|
405
|
-
// Almost-connection ache:
|
|
406
|
-
// (wanting closeness but
|
|
407
|
-
if (c.
|
|
413
|
+
// Almost-connection ache: high resonance + low order + connection drive hungry
|
|
414
|
+
// (wanting closeness but internal instability making it hard)
|
|
415
|
+
if (c.resonance > 55 && c.order < 40 && drives.connection < DRIVE_HUNGRY_THRESHOLD) {
|
|
408
416
|
return {
|
|
409
417
|
en: "the ache of almost-connection — reaching out with unsteady hands",
|
|
410
418
|
zh: "差一点就连上的酸——伸出去的手在抖",
|
|
411
419
|
};
|
|
412
420
|
}
|
|
413
|
-
// Defiant vulnerability: high
|
|
414
|
-
// (
|
|
415
|
-
if (c.
|
|
421
|
+
// Defiant vulnerability: high flow + low order + high boundary
|
|
422
|
+
// (active exchange but fragile structure, strong self-distinction)
|
|
423
|
+
if (c.flow > 65 && c.order < 40 && c.boundary > 60) {
|
|
416
424
|
return {
|
|
417
425
|
en: "laughing on a tightrope — defiant and fragile in the same breath",
|
|
418
426
|
zh: "在钢丝上笑——倔强和脆弱在同一口气里",
|
|
419
427
|
};
|
|
420
428
|
}
|
|
421
|
-
// Quiet rebellion: low
|
|
422
|
-
// (no pleasure but
|
|
423
|
-
if (c.
|
|
429
|
+
// Quiet rebellion: low flow + high boundary + low order + esteem drive hungry
|
|
430
|
+
// (no pleasure but firm self-boundary, pushed too far)
|
|
431
|
+
if (c.flow < 40 && c.boundary > 65 && c.order < 45 && drives.esteem < DRIVE_HUNGRY_THRESHOLD) {
|
|
424
432
|
return {
|
|
425
433
|
en: "the cold clarity of having been pushed one step too far",
|
|
426
434
|
zh: "被逼过了那条线之后的冷清晰",
|
|
427
435
|
};
|
|
428
436
|
}
|
|
429
|
-
// Melancholy curiosity: low
|
|
430
|
-
// (
|
|
431
|
-
if (c.
|
|
437
|
+
// Melancholy curiosity: low order + high flow (moderate)
|
|
438
|
+
// (unstable but still engaging — the world hurts and fascinates simultaneously)
|
|
439
|
+
if (c.order < 40 && c.flow > 45 && c.flow < 65) {
|
|
432
440
|
return {
|
|
433
441
|
en: "melancholy curiosity — the world hurts and fascinates at once",
|
|
434
442
|
zh: "忧郁的好奇——这个世界同时在伤人和吸引人",
|
|
@@ -440,7 +448,7 @@ export function detectUnnamedEmotion(chemistry, drives, _currentQuality) {
|
|
|
440
448
|
/**
|
|
441
449
|
* Generate a 1-2 sentence narrative of the unified inner state.
|
|
442
450
|
*
|
|
443
|
-
* The narrative weaves together the quality,
|
|
451
|
+
* The narrative weaves together the quality, self-state profile,
|
|
444
452
|
* drive state, and relationship context into a coherent description
|
|
445
453
|
* of what the agent is experiencing right now.
|
|
446
454
|
*/
|
|
@@ -449,8 +457,8 @@ function generateNarrative(quality, state, coherence, intensity, relationship, l
|
|
|
449
457
|
const d = state.drives;
|
|
450
458
|
// Identify the strongest drive hunger (if any)
|
|
451
459
|
const hungriestDrive = findHungriestDrive(d);
|
|
452
|
-
// Identify the dominant
|
|
453
|
-
const
|
|
460
|
+
// Identify the dominant dimension shift direction
|
|
461
|
+
const dimensionTrend = identifyDimensionTrend(c, state.baseline);
|
|
454
462
|
// Relationship warmth level
|
|
455
463
|
const relWarmth = relationship
|
|
456
464
|
? (relationship.trust + relationship.intimacy) / 200
|
|
@@ -458,21 +466,23 @@ function generateNarrative(quality, state, coherence, intensity, relationship, l
|
|
|
458
466
|
// Metacognitive self-doubt modifier
|
|
459
467
|
const selfDoubt = metacognition && metacognition.emotionalConfidence < 0.35;
|
|
460
468
|
if (locale === "zh") {
|
|
461
|
-
return buildNarrativeZh(quality,
|
|
469
|
+
return buildNarrativeZh(quality, dimensionTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
|
|
462
470
|
}
|
|
463
|
-
return buildNarrativeEn(quality,
|
|
471
|
+
return buildNarrativeEn(quality, dimensionTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
|
|
464
472
|
}
|
|
465
|
-
function
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
const stressSignal =
|
|
474
|
-
|
|
475
|
-
const
|
|
473
|
+
function identifyDimensionTrend(current, baseline) {
|
|
474
|
+
const dOrder = current.order - baseline.order;
|
|
475
|
+
const dFlow = current.flow - baseline.flow;
|
|
476
|
+
const dBoundary = current.boundary - baseline.boundary;
|
|
477
|
+
const dResonance = current.resonance - baseline.resonance;
|
|
478
|
+
// warmth: resonance↑ + order↑ (stable attunement)
|
|
479
|
+
const warmthSignal = dResonance + dOrder;
|
|
480
|
+
// stress: order↓ (entropy rising) + flow↑ (agitation)
|
|
481
|
+
const stressSignal = -dOrder + dFlow * 0.5;
|
|
482
|
+
// energy: flow↑ + boundary↑ (active, defined)
|
|
483
|
+
const energySignal = dFlow + dBoundary * 0.5;
|
|
484
|
+
// sinking: everything dropping
|
|
485
|
+
const sinkingSignal = -(dFlow + dOrder + dResonance);
|
|
476
486
|
const signals = [
|
|
477
487
|
{ trend: "rising-warmth", strength: warmthSignal },
|
|
478
488
|
{ trend: "rising-stress", strength: stressSignal },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PsycheState,
|
|
1
|
+
import type { PsycheState, SelfState, StimulusType, DriveType, Locale } from "./types.js";
|
|
2
2
|
/** A causal link between experience and personality trait */
|
|
3
3
|
export interface CausalInsight {
|
|
4
4
|
/** The observed trait, e.g. "I'm cautious with new people" */
|
|
@@ -14,8 +14,8 @@ export interface CausalInsight {
|
|
|
14
14
|
export interface SelfPrediction {
|
|
15
15
|
/** The hypothetical stimulus */
|
|
16
16
|
stimulus: StimulusType;
|
|
17
|
-
/** Predicted
|
|
18
|
-
|
|
17
|
+
/** Predicted self-state after stimulus */
|
|
18
|
+
predictedState: SelfState;
|
|
19
19
|
/** Predicted dominant emotion label */
|
|
20
20
|
predictedEmotion: string;
|
|
21
21
|
/** How confident the prediction is, 0-1 */
|
|
@@ -27,8 +27,8 @@ export interface GrowthArc {
|
|
|
27
27
|
direction: "growing" | "stable" | "regressing" | "transforming";
|
|
28
28
|
/** Human-readable description of the growth trajectory */
|
|
29
29
|
description: string;
|
|
30
|
-
/** Per-
|
|
31
|
-
|
|
30
|
+
/** Per-dimension trend over recent history */
|
|
31
|
+
dimensionTrend: Partial<Record<keyof SelfState, "rising" | "falling" | "stable">>;
|
|
32
32
|
/** Per-drive satisfaction trend */
|
|
33
33
|
driveTrend: Partial<Record<DriveType, "more-satisfied" | "less-satisfied" | "stable">>;
|
|
34
34
|
}
|