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.
Files changed (69) hide show
  1. package/README.md +58 -82
  2. package/dist/adapters/claude-sdk.d.ts +5 -5
  3. package/dist/adapters/claude-sdk.js +34 -32
  4. package/dist/adapters/mcp.js +4 -4
  5. package/dist/adapters/openclaw.js +12 -14
  6. package/dist/attachment.d.ts +3 -13
  7. package/dist/attachment.js +36 -88
  8. package/dist/autonomic.d.ts +4 -4
  9. package/dist/autonomic.js +28 -24
  10. package/dist/chemistry.d.ts +47 -21
  11. package/dist/chemistry.js +145 -91
  12. package/dist/circadian.d.ts +11 -43
  13. package/dist/circadian.js +24 -84
  14. package/dist/cli.js +37 -30
  15. package/dist/context-classifier.js +2 -2
  16. package/dist/core.d.ts +3 -3
  17. package/dist/core.js +99 -88
  18. package/dist/custom-profile.d.ts +20 -20
  19. package/dist/custom-profile.js +12 -12
  20. package/dist/decision-bias.d.ts +7 -8
  21. package/dist/decision-bias.js +74 -74
  22. package/dist/demo.js +5 -5
  23. package/dist/diagnostics.d.ts +6 -6
  24. package/dist/diagnostics.js +22 -22
  25. package/dist/drives.d.ts +15 -47
  26. package/dist/drives.js +98 -196
  27. package/dist/ethics.d.ts +3 -3
  28. package/dist/ethics.js +23 -23
  29. package/dist/experience.d.ts +34 -0
  30. package/dist/experience.js +200 -0
  31. package/dist/experiential-field.d.ts +19 -14
  32. package/dist/experiential-field.js +110 -100
  33. package/dist/generative-self.d.ts +5 -5
  34. package/dist/generative-self.js +124 -115
  35. package/dist/guards.d.ts +4 -4
  36. package/dist/guards.js +7 -7
  37. package/dist/i18n.js +61 -61
  38. package/dist/index.d.ts +8 -2
  39. package/dist/index.js +8 -1
  40. package/dist/input-turn.js +4 -6
  41. package/dist/interaction.d.ts +4 -4
  42. package/dist/interaction.js +10 -10
  43. package/dist/learning.d.ts +6 -6
  44. package/dist/learning.js +18 -18
  45. package/dist/metacognition.d.ts +2 -2
  46. package/dist/metacognition.js +79 -94
  47. package/dist/perceive.d.ts +44 -0
  48. package/dist/perceive.js +231 -0
  49. package/dist/primary-systems.d.ts +2 -2
  50. package/dist/primary-systems.js +21 -19
  51. package/dist/profiles.d.ts +5 -13
  52. package/dist/profiles.js +33 -51
  53. package/dist/prompt.d.ts +2 -2
  54. package/dist/prompt.js +51 -53
  55. package/dist/psyche-file.d.ts +7 -7
  56. package/dist/psyche-file.js +77 -78
  57. package/dist/relation-dynamics.d.ts +4 -0
  58. package/dist/relation-dynamics.js +1 -1
  59. package/dist/reply-envelope.d.ts +25 -1
  60. package/dist/reply-envelope.js +26 -11
  61. package/dist/self-recognition.d.ts +3 -3
  62. package/dist/self-recognition.js +17 -17
  63. package/dist/subjectivity.js +7 -7
  64. package/dist/temporal.d.ts +6 -6
  65. package/dist/temporal.js +37 -39
  66. package/dist/types.d.ts +67 -45
  67. package/dist/types.js +55 -51
  68. package/package.json +1 -1
  69. 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
- // Chemistry readouts describe individual neurotransmitter levels.
10
- // The experiential field describes what those levels feel like when
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 { CHEMICAL_KEYS, DRIVE_KEYS } from "./types.js";
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 chemistry to valence + arousal — the two fundamental affective dimensions
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(chemistry) {
30
- const { DA, HT, OT, END, CORT, NE } = chemistry;
31
- // Valence: positive chemicals push up, stress pushes down
32
- // CORT weighted 1.5× (cortisol is the dominant negative signal)
33
- // NE weighted 0.5× (arousing but not inherently negative)
34
- const rawValence = (DA - 50) + (HT - 50) + (OT - 50) + (END - 50) - (CORT - 50) * 1.5 - (NE - 50) * 0.5;
35
- const valence = Math.max(-1, Math.min(1, rawValence / 250));
36
- // Arousal: NE dominant, CORT and DA contribute
37
- const rawArousal = NE + CORT * 0.5 + DA * 0.3;
38
- const arousal = Math.max(0, Math.min(1, rawArousal / 180));
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 chemistry, drives,
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: chemistry, drives, and relationship state all tell
89
- * the same story. Happy chemicals + satisfied drives + warm relationship = unified.
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 DA but high CORT. Satisfied drives
92
- * but stressed chemistry. Warm relationship but depleted OT. The psyche
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
- // ── Chemistry internal coherence ──
98
- // Reward chemicals (DA, END) should not coexist with high stress (CORT)
99
- const rewardSignal = (current.DA + current.END) / 200; // 0-1
100
- const stressSignal = current.CORT / 100;
101
- const rewardStressConflict = rewardSignal * stressSignal;
102
- coherenceScore -= rewardStressConflict * 0.4;
103
- // Bonding (OT) and threat (CORT + NE) should not coexist strongly
104
- const bondingSignal = current.OT / 100;
105
- const bondingThreatConflict = bondingSignal * (stressSignal > 0.55 ? stressSignal : 0);
106
- coherenceScore -= bondingThreatConflict * 0.3;
107
- // ── Chemistry-Drive alignment ──
108
- // If drives are satisfied, positive chemistry is coherent.
109
- // If drives are hungry, negative chemistry is coherent (the distress makes sense).
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 avgPositiveChemistry = (norm(current.DA) + norm(current.HT) + norm(current.OT) + norm(current.END)) / 4;
113
- const avgNegativeChemistry = (norm(current.CORT) + (1 - norm(current.HT))) / 2;
114
- // Satisfied drives + positive chemistry = coherent (no penalty)
115
- // Satisfied drives + negative chemistry = incoherent
116
- // Hungry drives + negative chemistry = coherent (no penalty)
117
- // Hungry drives + positive chemistry = incoherent (but less so — hope is valid)
118
- if (avgDriveSatisfaction > 0.6 && avgNegativeChemistry > 0.5) {
119
- coherenceScore -= (avgDriveSatisfaction - 0.6) * avgNegativeChemistry * 0.5;
120
- }
121
- if (avgDriveSatisfaction < 0.4 && avgPositiveChemistry > 0.6) {
122
- coherenceScore -= (0.4 - avgDriveSatisfaction) * (avgPositiveChemistry - 0.6) * 0.3;
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 OT; low trust with low OT
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 otLevel = norm(current.OT);
129
- const relChemMismatch = Math.abs(relWarmth - otLevel);
130
- if (relChemMismatch > 0.3) {
131
- coherenceScore -= (relChemMismatch - 0.3) * 0.25;
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 CHEMICAL_KEYS) {
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
- // 15 pairs total (6 choose 2); normalize
150
- coherenceScore -= (opposingDeviations / 15) * 0.3;
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 CHEMICAL_KEYS) {
168
+ for (const key of DIMENSION_KEYS) {
164
169
  totalDeviation += Math.abs(current[key] - baseline[key]);
165
170
  }
166
- // Max possible deviation = 6 chemicals * 100 = 600
167
- // But realistic maximum is around 300 (chemicals cluster toward extremes)
168
- // Map so that deviation of ~120 (avg 20 per chemical) = 0.5 intensity
169
- return clamp01(totalDeviation / 240);
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. Chemistry → valence + arousal (Russell Circumplex)
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: Chemistry → Affect Core ──
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.chemistry);
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 chemical configurations that don't map to any of the 14 named
376
- * emotions in chemistry.ts — novel experiential states that need
377
- * descriptive phrases rather than labels.
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(chemistry, drives, _currentQuality) {
380
- const c = chemistry;
381
- // Nostalgia-but-forward: OT high + DA moderately high + NE high
382
- // (warmth for the past + excitement for what's next)
383
- if (c.OT > 60 && c.DA > 55 && c.NE > 60 && c.CORT < 40) {
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: high CORT + high OT + high NE
390
- // (protectiveness, caring that has teeth)
391
- if (c.CORT > 55 && c.OT > 60 && c.NE > 60) {
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 DA + moderate CORT + low connection
405
+ // Bittersweet accomplishment: high flow + moderate-low order + low connection drive
398
406
  // (achieved something but nobody to share it with)
399
- if (c.DA > 65 && c.CORT > 40 && c.CORT < 60 && drives.connection < DRIVE_HUNGRY_THRESHOLD) {
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: OT moderate-high + HT low + connection drive hungry
406
- // (wanting closeness but mood instability making it hard)
407
- if (c.OT > 55 && c.HT < 40 && drives.connection < DRIVE_HUNGRY_THRESHOLD) {
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 NE + low HT + high END
414
- // (wired but fragile, laughing on the edge)
415
- if (c.NE > 65 && c.HT < 40 && c.END > 60) {
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 DA + high NE + high CORT + esteem drive hungry
422
- // (no pleasure but plenty of fight, pushed too far)
423
- if (c.DA < 40 && c.NE > 65 && c.CORT > 55 && drives.esteem < DRIVE_HUNGRY_THRESHOLD) {
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 HT + high NE + DA moderate
430
- // (sad but still interested — the world hurts and fascinates simultaneously)
431
- if (c.HT < 40 && c.NE > 60 && c.DA > 45 && c.DA < 65) {
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, chemistry profile,
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 chemical shift direction
453
- const chemTrend = identifyChemicalTrend(c, state.baseline);
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, chemTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
469
+ return buildNarrativeZh(quality, dimensionTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
462
470
  }
463
- return buildNarrativeEn(quality, chemTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
471
+ return buildNarrativeEn(quality, dimensionTrend, hungriestDrive, relWarmth, coherence, intensity, selfDoubt);
464
472
  }
465
- function identifyChemicalTrend(current, baseline) {
466
- const dDA = current.DA - baseline.DA;
467
- const dHT = current.HT - baseline.HT;
468
- const dCORT = current.CORT - baseline.CORT;
469
- const dOT = current.OT - baseline.OT;
470
- const dNE = current.NE - baseline.NE;
471
- const dEND = current.END - baseline.END;
472
- const warmthSignal = dOT + dHT + dEND;
473
- const stressSignal = dCORT + dNE - dHT;
474
- const energySignal = dDA + dNE + dEND;
475
- const sinkingSignal = -(dDA + dNE + dEND + dHT);
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, ChemicalState, StimulusType, DriveType, Locale } from "./types.js";
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 chemical deltas */
18
- predictedChemistry: ChemicalState;
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-chemical trend over recent history */
31
- chemicalTrend: Partial<Record<keyof ChemicalState, "rising" | "falling" | "stable">>;
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
  }