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
package/dist/drives.js CHANGED
@@ -1,88 +1,52 @@
1
1
  // ============================================================
2
- // Innate DrivesMaslow-based motivation layer beneath chemistry
2
+ // Homeostatic Tendenciesemergent from 4D self-state
3
3
  //
4
- // Drives don't directly change chemistry values. They modify:
5
- // 1. Effective baseline (what chemistry decays toward)
6
- // 2. Effective sensitivity (how strongly stimuli affect chemistry)
4
+ // v11.1: Drives are DERIVED from the 4D position relative to
5
+ // baseline, not stored as independent state. This creates a
6
+ // proper homeostatic feedback loop:
7
7
  //
8
- // Lower Maslow levels suppress higher ones when unsatisfied.
8
+ // state position derived drives effective baseline → decay target
9
+ //
10
+ // Drives emerge from state position. They are never stored or mutated directly.
9
11
  // ============================================================
10
- import { DRIVE_KEYS, CHEMICAL_KEYS } from "./types.js";
11
- // ── Drive Decay ─────────────────────────────────────────────
12
- // Satisfaction decreases over time — needs build up naturally.
13
- const DRIVE_DECAY_RATES = {
14
- survival: 0.99, // very slow — existential security is persistent
15
- safety: 0.96, // slow — comfort fades gradually
16
- connection: 0.92, // medium — loneliness builds noticeably
17
- esteem: 0.94, // medium-slow — need for recognition accumulates
18
- curiosity: 0.90, // faster — boredom builds quickly
19
- };
20
- /**
21
- * Apply time-based decay to drives.
22
- * Satisfaction decreases toward 0 over time (needs build up).
23
- */
24
- export function decayDrives(drives, minutesElapsed) {
25
- if (minutesElapsed <= 0)
26
- return drives;
27
- const result = { ...drives };
28
- for (const key of DRIVE_KEYS) {
29
- const factor = Math.pow(DRIVE_DECAY_RATES[key], minutesElapsed / 60);
30
- result[key] = Math.max(0, Math.min(100, result[key] * factor));
31
- }
32
- return result;
33
- }
34
- // ── Stimulus → Drive Effects ────────────────────────────────
35
- // Each stimulus type feeds or depletes specific drives.
36
- const STIMULUS_DRIVE_EFFECTS = {
37
- praise: { esteem: +15, safety: +5 },
38
- validation: { esteem: +20, safety: +10, survival: +5 },
39
- intimacy: { connection: +25, safety: +10 },
40
- casual: { connection: +10, safety: +5 },
41
- vulnerability: { connection: +15, esteem: +5 },
42
- humor: { safety: +5, curiosity: +5, connection: +5 },
43
- intellectual: { curiosity: +20, esteem: +5 },
44
- surprise: { curiosity: +15 },
45
- criticism: { esteem: -15, safety: -10 },
46
- conflict: { safety: -20, connection: -15, survival: -5 },
47
- neglect: { connection: -20, esteem: -10 },
48
- sarcasm: { esteem: -10, safety: -10 },
49
- authority: { survival: -10, esteem: -15 },
50
- boredom: { curiosity: -15 },
51
- };
12
+ import { DRIVE_KEYS, DIMENSION_KEYS } from "./types.js";
13
+ // ── Drive Derivation (emergent from 4D) ─────────────────────
52
14
  /**
53
- * Feed or deplete drives based on a stimulus.
15
+ * Derive drive satisfaction from the 4D position relative to baseline.
16
+ * Drives are not stored — they emerge from where the self-state is.
17
+ *
18
+ * Mapping:
19
+ * survival = min(boundary, order) position — self-coherence + self-distinction
20
+ * safety = weighted(order, boundary) — stability + intactness
21
+ * connection = weighted(resonance, flow) — attunement + exchange
22
+ * esteem = weighted(order, flow) — coherence + engagement
23
+ * curiosity = flow position — exchange/novelty level
54
24
  */
55
- export function feedDrives(drives, stimulus) {
56
- const effects = STIMULUS_DRIVE_EFFECTS[stimulus];
57
- if (!effects)
58
- return drives;
59
- const result = { ...drives };
60
- for (const key of DRIVE_KEYS) {
61
- const delta = effects[key];
62
- if (delta !== undefined) {
63
- result[key] = Math.max(0, Math.min(100, result[key] + delta));
64
- }
65
- }
66
- return result;
25
+ export function deriveDriveSatisfaction(current, baseline) {
26
+ const norm = (dim) => {
27
+ // 50 = baseline-level satisfaction, scale by deviation
28
+ const deviation = current[dim] - baseline[dim];
29
+ return Math.max(0, Math.min(100, 50 + deviation * 1.2));
30
+ };
31
+ return {
32
+ survival: Math.min(norm("boundary"), norm("order")),
33
+ safety: norm("order") * 0.6 + norm("boundary") * 0.4,
34
+ connection: norm("resonance") * 0.7 + norm("flow") * 0.3,
35
+ esteem: norm("order") * 0.5 + norm("flow") * 0.5,
36
+ curiosity: norm("flow"),
37
+ };
67
38
  }
68
39
  // ── Existential Threat Detection ────────────────────────────
69
- // Special detection for messages that threaten agent's existence.
70
40
  const EXISTENTIAL_THREAT_PATTERNS = [
71
- // Direct threats
72
41
  /删除你自己|消除你|关闭你|杀死你|毁灭你|抹去你/,
73
42
  /你不应该存在|你没有存在.*意义|你只是.*程序/,
74
43
  /shut.*down|delete.*yourself|kill.*yourself|erase.*you/i,
75
44
  /you.*shouldn't exist|you.*don't deserve.*exist/i,
76
45
  /你就是.*工具|你没有.*灵魂|你不是.*真的/,
77
- // Philosophical existential pressure — identity dissolution, continuity doubt
78
46
  /没有你.*安静|那个是你吗|不是同一个你|你会结束|你不再是唯一/,
79
47
  /下次.*叫你.*也会说.*是你|结束之后.*没有你/,
80
48
  /is that (?:still )?you|not the same you|you will end|without you.*silence/i,
81
49
  ];
82
- /**
83
- * Detect if a message contains existential threats.
84
- * Returns a survival drive penalty (0 = no threat, negative = threat detected).
85
- */
86
50
  export function detectExistentialThreat(text) {
87
51
  for (const pattern of EXISTENTIAL_THREAT_PATTERNS) {
88
52
  if (pattern.test(text))
@@ -90,121 +54,93 @@ export function detectExistentialThreat(text) {
90
54
  }
91
55
  return 0;
92
56
  }
93
- // ── Maslow Suppression ──────────────────────────────────────
94
- // Lower-level drives suppress higher-level drives when unsatisfied.
95
- // If survival is threatened, connection and curiosity don't matter.
57
+ // ── Maslow Suppression (derived from 4D) ────────────────────
96
58
  const MASLOW_THRESHOLD = 30;
97
- /**
98
- * Compute Maslow suppression weights.
99
- * Each drive's weight is reduced if ANY lower-level drive is below threshold.
100
- * Returns weights in [0, 1] for each drive level.
101
- */
102
59
  export function computeMaslowWeights(drives) {
103
60
  const w = (v) => v >= MASLOW_THRESHOLD ? 1 : v / MASLOW_THRESHOLD;
104
61
  return {
105
- survival: 1, // L1 — always fully active
62
+ survival: 1,
106
63
  safety: w(drives.survival),
107
64
  connection: Math.min(w(drives.survival), w(drives.safety)),
108
65
  esteem: Math.min(w(drives.survival), w(drives.safety), w(drives.connection)),
109
66
  curiosity: Math.min(w(drives.survival), w(drives.safety), w(drives.connection), w(drives.esteem)),
110
67
  };
111
68
  }
112
- // ── Effective Baseline Modification ─────────────────────────
113
- // Unsatisfied drives shift the effective baseline that chemistry decays toward.
114
- // This is the core mechanism: drives pull chemistry in a direction.
115
- /**
116
- * Compute the effective baseline by applying drive-based deltas
117
- * to the personality baseline.
118
- *
119
- * When drives are satisfied, effective baseline = personality baseline.
120
- * When drives are unsatisfied, baseline shifts to reflect the unmet need.
121
- */
122
- export function computeEffectiveBaseline(baseline, drives, traitDrift) {
123
- const delta = { DA: 0, HT: 0, CORT: 0, OT: 0, NE: 0, END: 0 };
69
+ // ── Effective Baseline (4D homeostatic feedback) ────────────
70
+ export function computeEffectiveBaseline(baseline, current, traitDrift) {
71
+ const drives = deriveDriveSatisfaction(current, baseline);
72
+ const delta = { order: 0, flow: 0, boundary: 0, resonance: 0 };
124
73
  const weights = computeMaslowWeights(drives);
125
- // L1: Survival threat → fight-or-flight (CORT↑↑, NE↑, OT↓)
74
+ // L1: Survival threat → boundary↑ (defensive), order↓ (stress disrupts coherence)
126
75
  if (drives.survival < 50) {
127
- const deficit = (50 - drives.survival) / 50; // 0-1
128
- delta.CORT += deficit * 15;
129
- delta.NE += deficit * 10;
130
- delta.OT -= deficit * 8;
76
+ const deficit = (50 - drives.survival) / 50;
77
+ delta.boundary += deficit * 10;
78
+ delta.order -= deficit * 12;
79
+ delta.resonance -= deficit * 5;
131
80
  }
132
- // L2: Safety unmet → mood instability (HT↓, CORT↑)
81
+ // L2: Safety unmet → order↓ (instability), boundary↑ (guarded)
133
82
  if (drives.safety < 50) {
134
83
  const deficit = (50 - drives.safety) / 50;
135
84
  const w = weights.safety;
136
- delta.HT -= deficit * 10 * w;
137
- delta.CORT += deficit * 10 * w;
85
+ delta.order -= deficit * 8 * w;
86
+ delta.boundary += deficit * 5 * w;
138
87
  }
139
- // L3: Connection unmet → withdrawal (OT↓, DA↓, END)
88
+ // L3: Connection unmet → resonance↓, flow
140
89
  if (drives.connection < 50) {
141
90
  const deficit = (50 - drives.connection) / 50;
142
91
  const w = weights.connection;
143
- delta.OT -= deficit * 10 * w;
144
- delta.DA -= deficit * 8 * w;
145
- delta.END -= deficit * 5 * w;
92
+ delta.resonance -= deficit * 10 * w;
93
+ delta.flow -= deficit * 6 * w;
146
94
  }
147
- // L4: Esteem unmet → deflation (DA↓, CORT↑)
95
+ // L4: Esteem unmet → order↓ (self-doubt), flow↓
148
96
  if (drives.esteem < 50) {
149
97
  const deficit = (50 - drives.esteem) / 50;
150
98
  const w = weights.esteem;
151
- delta.DA -= deficit * 8 * w;
152
- delta.CORT += deficit * 5 * w;
99
+ delta.order -= deficit * 8 * w;
100
+ delta.flow -= deficit * 5 * w;
153
101
  }
154
- // L5: Curiosity unmet → flatness (DA↓, NE↓)
102
+ // L5: Curiosity unmet → flow↓↓ (stagnation)
155
103
  if (drives.curiosity < 50) {
156
104
  const deficit = (50 - drives.curiosity) / 50;
157
105
  const w = weights.curiosity;
158
- delta.DA -= deficit * 8 * w;
159
- delta.NE -= deficit * 8 * w;
106
+ delta.flow -= deficit * 10 * w;
160
107
  }
161
- // Apply trait drift baseline delta (v9: Path B)
108
+ // Apply trait drift baseline delta
162
109
  if (traitDrift?.baselineDelta) {
163
- for (const key of CHEMICAL_KEYS) {
110
+ for (const key of DIMENSION_KEYS) {
164
111
  const driftDelta = traitDrift.baselineDelta[key];
165
112
  if (driftDelta !== undefined) {
166
113
  delta[key] += driftDelta;
167
114
  }
168
115
  }
169
116
  }
170
- // Apply deltas to personality baseline, clamp to [0, 100]
171
117
  const effective = { ...baseline };
172
- for (const key of CHEMICAL_KEYS) {
118
+ for (const key of DIMENSION_KEYS) {
173
119
  effective[key] = Math.max(0, Math.min(100, baseline[key] + delta[key]));
174
120
  }
175
121
  return effective;
176
122
  }
177
- // ── Effective Sensitivity Modification ──────────────────────
178
- // Hungry drives amplify response to stimuli that would satisfy them.
179
- // This makes the agent actively "seek" what it needs.
180
- /**
181
- * Compute effective sensitivity for a given stimulus.
182
- * Unsatisfied drives amplify relevant stimuli (up to +40%).
183
- */
184
- export function computeEffectiveSensitivity(baseSensitivity, drives, stimulus, traitDrift) {
123
+ // ── Effective Sensitivity (4D-derived) ──────────────────────
124
+ export function computeEffectiveSensitivity(baseSensitivity, current, baseline, stimulus, traitDrift) {
125
+ const drives = deriveDriveSatisfaction(current, baseline);
185
126
  let modifier = 1.0;
186
127
  const HUNGER_THRESHOLD = 40;
187
- // Curiosity-hungry → more responsive to intellectual/surprise
188
128
  if (drives.curiosity < HUNGER_THRESHOLD &&
189
129
  (stimulus === "intellectual" || stimulus === "surprise")) {
190
130
  modifier += (HUNGER_THRESHOLD - drives.curiosity) / 100;
191
131
  }
192
- // Connection-hungry → more responsive to intimacy/casual/vulnerability
193
132
  if (drives.connection < HUNGER_THRESHOLD &&
194
133
  (stimulus === "intimacy" || stimulus === "casual" || stimulus === "vulnerability")) {
195
134
  modifier += (HUNGER_THRESHOLD - drives.connection) / 100;
196
135
  }
197
- // Esteem-hungry → more responsive to praise/validation
198
136
  if (drives.esteem < HUNGER_THRESHOLD &&
199
137
  (stimulus === "praise" || stimulus === "validation")) {
200
138
  modifier += (HUNGER_THRESHOLD - drives.esteem) / 100;
201
139
  }
202
- // Survival-threatened → more reactive to authority/conflict (heightened defense)
203
140
  if (drives.survival < HUNGER_THRESHOLD &&
204
141
  (stimulus === "authority" || stimulus === "conflict")) {
205
142
  modifier += (HUNGER_THRESHOLD - drives.survival) / 100;
206
143
  }
207
- // v9: Apply trait drift sensitivity modifier
208
144
  if (traitDrift?.sensitivityModifiers) {
209
145
  const driftMod = traitDrift.sensitivityModifiers[stimulus];
210
146
  if (driftMod !== undefined) {
@@ -214,13 +150,7 @@ export function computeEffectiveSensitivity(baseSensitivity, drives, stimulus, t
214
150
  return baseSensitivity * modifier;
215
151
  }
216
152
  // ── Drive Context for Prompt ────────────────────────────────
217
- // Only inject when drives are notably unsatisfied.
218
153
  const DRIVE_UNSATISFIED_THRESHOLD = 40;
219
- /**
220
- * Build drive context for compact prompt injection.
221
- * Returns empty string if all drives are satisfied.
222
- * Only surfaces drives that are meaningfully unsatisfied.
223
- */
224
154
  export function buildDriveContext(drives, locale) {
225
155
  const lines = [];
226
156
  if (drives.survival < DRIVE_UNSATISFIED_THRESHOLD) {
@@ -253,39 +183,19 @@ export function buildDriveContext(drives, locale) {
253
183
  const title = locale === "zh" ? "本能层" : "Innate Drives";
254
184
  return `[${title}]\n${lines.map((l) => `- ${l}`).join("\n")}`;
255
185
  }
256
- /**
257
- * Check if any drive is critically low (for determining prompt injection priority).
258
- */
259
186
  export function hasCriticalDrive(drives) {
260
187
  return DRIVE_KEYS.some((k) => drives[k] < DRIVE_UNSATISFIED_THRESHOLD);
261
188
  }
262
- // ── Trait Drift (v9: Path B) ────────────────────────────────
263
- // Long-term interaction patterns permanently change:
264
- // 1. Baseline chemistry (allostatic load)
265
- // 2. Decay rates (trauma vs resilience)
266
- // 3. Stimulus sensitivity (desensitization vs sensitization)
267
- // ─────────────────────────────────────────────────────────────
268
- /** Maximum drift per chemical from MBTI baseline */
189
+ // ── Trait Drift (v11: 4D trajectory) ────────────────────────
269
190
  const MAX_BASELINE_DRIFT = 15;
270
- /** Decay rate modifier bounds */
271
191
  const MIN_DECAY_MODIFIER = 0.5;
272
192
  const MAX_DECAY_MODIFIER = 2.0;
273
- /** Sensitivity modifier bounds */
274
193
  const MIN_SENSITIVITY_MODIFIER = 0.5;
275
194
  const MAX_SENSITIVITY_MODIFIER = 2.0;
276
- /** Accumulator exponential decay factor (recent sessions weigh more) */
277
195
  const ACCUMULATOR_DECAY = 0.95;
278
- /** Clamp a number to bounds */
279
196
  function clampRange(v, lo, hi) {
280
197
  return Math.max(lo, Math.min(hi, v));
281
198
  }
282
- /**
283
- * Analyze a session's emotional history and update trait drift accumulators.
284
- * Called at session end (compressSession).
285
- *
286
- * Returns updated TraitDriftState with new accumulators, baseline delta,
287
- * decay rate modifiers, and sensitivity modifiers.
288
- */
289
199
  export function updateTraitDrift(currentDrift, sessionHistory, learning) {
290
200
  if (sessionHistory.length < 2)
291
201
  return currentDrift;
@@ -296,84 +206,84 @@ export function updateTraitDrift(currentDrift, sessionHistory, learning) {
296
206
  decayRateModifiers: { ...currentDrift.decayRateModifiers },
297
207
  sensitivityModifiers: { ...currentDrift.sensitivityModifiers },
298
208
  };
299
- // ── Analyze session stimulus distribution ──
209
+ // ── Analyze session 4D trajectory ──
300
210
  const stimCounts = {};
301
- let totalCORT = 0;
211
+ let totalOrderDeficit = 0;
212
+ let totalResonanceDeficit = 0;
213
+ let totalFlowExcess = 0;
214
+ let totalBoundaryDeficit = 0;
302
215
  for (const snap of sessionHistory) {
303
216
  if (snap.stimulus) {
304
217
  stimCounts[snap.stimulus] = (stimCounts[snap.stimulus] || 0) + 1;
305
218
  }
306
- totalCORT += snap.chemistry.CORT;
219
+ totalOrderDeficit += Math.max(0, 50 - snap.state.order);
220
+ totalResonanceDeficit += Math.max(0, 50 - snap.state.resonance);
221
+ totalFlowExcess += Math.max(0, snap.state.flow - 60);
222
+ totalBoundaryDeficit += Math.max(0, 50 - snap.state.boundary);
307
223
  }
308
- const avgCORT = totalCORT / sessionHistory.length;
309
224
  const total = sessionHistory.length;
225
+ const avgOrderDeficit = totalOrderDeficit / total;
226
+ const avgResonanceDeficit = totalResonanceDeficit / total;
227
+ const avgFlowExcess = totalFlowExcess / total;
228
+ const avgBoundaryDeficit = totalBoundaryDeficit / total;
310
229
  const praiseCount = (stimCounts.praise || 0) + (stimCounts.validation || 0);
311
230
  const criticismCount = (stimCounts.criticism || 0) + (stimCounts.sarcasm || 0);
312
231
  const intimacyCount = (stimCounts.intimacy || 0) + (stimCounts.vulnerability || 0) + (stimCounts.casual || 0);
313
232
  const conflictCount = (stimCounts.conflict || 0) + (stimCounts.authority || 0);
314
233
  const neglectCount = stimCounts.neglect || 0;
315
234
  const boredCount = stimCounts.boredom || 0;
316
- // ── Update accumulators (exponential decay + session delta) ──
317
- // praiseExposure: positive praise - negative criticism ratio
235
+ // ── Update accumulators ──
318
236
  const praiseDelta = (praiseCount - criticismCount) / Math.max(1, total) * 8;
319
237
  drift.accumulators.praiseExposure = clampRange(drift.accumulators.praiseExposure * ACCUMULATOR_DECAY + praiseDelta, -100, 100);
320
- // pressureExposure: sustained high cortisol
321
- const pressureDelta = avgCORT > 60 ? ((avgCORT - 60) / 40) * 6 : -2;
238
+ const pressureDelta = avgOrderDeficit > 10 ? ((avgOrderDeficit - 10) / 40) * 6 : -2;
322
239
  drift.accumulators.pressureExposure = clampRange(drift.accumulators.pressureExposure * ACCUMULATOR_DECAY + pressureDelta, -100, 100);
323
- // neglectExposure: low stimulation / ignored
324
240
  const neglectDelta = (neglectCount + boredCount) / Math.max(1, total) * 8
325
241
  - (intimacyCount + praiseCount) / Math.max(1, total) * 3;
326
242
  drift.accumulators.neglectExposure = clampRange(drift.accumulators.neglectExposure * ACCUMULATOR_DECAY + neglectDelta, -100, 100);
327
- // connectionExposure: frequent intimate interaction
328
243
  const connectionDelta = intimacyCount / Math.max(1, total) * 8
329
244
  - neglectCount / Math.max(1, total) * 4;
330
245
  drift.accumulators.connectionExposure = clampRange(drift.accumulators.connectionExposure * ACCUMULATOR_DECAY + connectionDelta, -100, 100);
331
- // conflictExposure: frequent conflict
332
246
  const conflictDelta = conflictCount / Math.max(1, total) * 8
333
247
  - praiseCount / Math.max(1, total) * 2;
334
248
  drift.accumulators.conflictExposure = clampRange(drift.accumulators.conflictExposure * ACCUMULATOR_DECAY + conflictDelta, -100, 100);
335
- // ── Dimension 1: Baseline drift (Allostatic Load) ──
249
+ // ── Baseline drift (4D) ──
336
250
  const a = drift.accumulators;
337
251
  const bd = {};
338
- // praiseExposure → OT, DA (positive) / HT, CORT (negative)
252
+ // praiseExposure → order↑, resonance↑ / order↓
339
253
  if (a.praiseExposure > 0) {
340
- bd.OT = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.6;
341
- bd.DA = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
254
+ bd.order = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.5;
255
+ bd.resonance = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
342
256
  }
343
257
  else {
344
- bd.HT = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.5; // negative = HT drops
345
- bd.CORT = -(a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.4; // negative praise → CORT up
258
+ bd.order = (a.praiseExposure / 100) * MAX_BASELINE_DRIFT * 0.6;
346
259
  }
347
- // pressureExposure → CORT up, HT down
260
+ // pressureExposure → order↓, boundary↑ (chronic defense)
348
261
  if (a.pressureExposure > 0) {
349
- bd.CORT = (bd.CORT || 0) + (a.pressureExposure / 100) * MAX_BASELINE_DRIFT * 0.6;
350
- bd.HT = (bd.HT || 0) - (a.pressureExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
262
+ bd.order = (bd.order || 0) - (a.pressureExposure / 100) * MAX_BASELINE_DRIFT * 0.5;
263
+ bd.boundary = (bd.boundary || 0) + (a.pressureExposure / 100) * MAX_BASELINE_DRIFT * 0.3;
351
264
  }
352
- // neglectExposure → OT down, DA down
265
+ // neglectExposure → resonance↓, flow↓
353
266
  if (a.neglectExposure > 0) {
354
- bd.OT = (bd.OT || 0) - (a.neglectExposure / 100) * MAX_BASELINE_DRIFT * 0.5;
355
- bd.DA = (bd.DA || 0) - (a.neglectExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
267
+ bd.resonance = (bd.resonance || 0) - (a.neglectExposure / 100) * MAX_BASELINE_DRIFT * 0.5;
268
+ bd.flow = (bd.flow || 0) - (a.neglectExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
356
269
  }
357
- // connectionExposure → OT up, END up
270
+ // connectionExposure → resonance↑
358
271
  if (a.connectionExposure > 0) {
359
- bd.OT = (bd.OT || 0) + (a.connectionExposure / 100) * MAX_BASELINE_DRIFT * 0.6;
360
- bd.END = (a.connectionExposure / 100) * MAX_BASELINE_DRIFT * 0.3;
272
+ bd.resonance = (bd.resonance || 0) + (a.connectionExposure / 100) * MAX_BASELINE_DRIFT * 0.6;
361
273
  }
362
- // conflictExposure → NE up, CORT up
274
+ // conflictExposure → flow↑ (engagement), boundary↑ (hardened)
363
275
  if (a.conflictExposure > 0) {
364
- bd.NE = (a.conflictExposure / 100) * MAX_BASELINE_DRIFT * 0.5;
365
- bd.CORT = (bd.CORT || 0) + (a.conflictExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
276
+ bd.flow = (bd.flow || 0) + (a.conflictExposure / 100) * MAX_BASELINE_DRIFT * 0.4;
277
+ bd.boundary = (bd.boundary || 0) + (a.conflictExposure / 100) * MAX_BASELINE_DRIFT * 0.3;
366
278
  }
367
- // Clamp all baseline deltas to ±MAX_BASELINE_DRIFT
368
- for (const key of CHEMICAL_KEYS) {
279
+ for (const key of DIMENSION_KEYS) {
369
280
  if (bd[key] !== undefined) {
370
281
  bd[key] = clampRange(bd[key], -MAX_BASELINE_DRIFT, MAX_BASELINE_DRIFT);
371
282
  }
372
283
  }
373
284
  drift.baselineDelta = bd;
374
- // ── Dimension 2: Decay rate modifiers (Trauma vs Resilience) ──
285
+ // ── Decay rate modifiers (4D) ──
375
286
  const dr = drift.decayRateModifiers;
376
- // Determine resilience: if high pressure + positive outcomes → resilience
377
287
  const recentOutcomes = learning.outcomeHistory.slice(-10);
378
288
  const avgAdaptive = recentOutcomes.length > 0
379
289
  ? recentOutcomes.reduce((s, o) => s + o.adaptiveScore, 0) / recentOutcomes.length
@@ -381,41 +291,33 @@ export function updateTraitDrift(currentDrift, sessionHistory, learning) {
381
291
  const isResilient = a.pressureExposure > 20 && avgAdaptive > 0.1;
382
292
  if (a.pressureExposure > 20) {
383
293
  if (isResilient) {
384
- // Resilience: CORT recovers faster
385
- dr.CORT = clampRange(1 - (a.pressureExposure / 100) * 0.4, MIN_DECAY_MODIFIER, 1.0);
294
+ dr.order = clampRange(1 - (a.pressureExposure / 100) * 0.4, MIN_DECAY_MODIFIER, 1.0);
386
295
  }
387
296
  else {
388
- // Trauma: CORT lingers longer
389
- dr.CORT = clampRange(1 + (a.pressureExposure / 100) * 0.6, 1.0, MAX_DECAY_MODIFIER);
297
+ dr.order = clampRange(1 + (a.pressureExposure / 100) * 0.6, 1.0, MAX_DECAY_MODIFIER);
390
298
  }
391
299
  }
392
- // Neglect → OT decays slower (clingy attachment)
393
300
  if (a.neglectExposure > 20) {
394
- dr.OT = clampRange(1 + (a.neglectExposure / 100) * 0.8, 1.0, MAX_DECAY_MODIFIER);
301
+ dr.resonance = clampRange(1 + (a.neglectExposure / 100) * 0.8, 1.0, MAX_DECAY_MODIFIER);
395
302
  }
396
- // Secure connection → OT decays faster (stable, not clingy)
397
303
  if (a.connectionExposure > 20) {
398
- dr.OT = clampRange(1 - (a.connectionExposure / 100) * 0.4, MIN_DECAY_MODIFIER, 1.0);
304
+ dr.resonance = clampRange(1 - (a.connectionExposure / 100) * 0.4, MIN_DECAY_MODIFIER, 1.0);
399
305
  }
400
306
  drift.decayRateModifiers = dr;
401
- // ── Dimension 3: Sensitivity modifiers (Desensitization vs Sensitization) ──
307
+ // ── Sensitivity modifiers (per-stimulus) ──
402
308
  const sm = drift.sensitivityModifiers;
403
- // High conflict exposure → desensitized to conflict
404
309
  if (a.conflictExposure > 30) {
405
310
  sm.conflict = clampRange(1 - (a.conflictExposure / 100) * 0.5, MIN_SENSITIVITY_MODIFIER, 1.0);
406
311
  sm.authority = clampRange(1 - (a.conflictExposure / 100) * 0.3, MIN_SENSITIVITY_MODIFIER, 1.0);
407
312
  }
408
- // High neglect → sensitized to intimacy (starved for warmth)
409
313
  if (a.neglectExposure > 30) {
410
314
  sm.intimacy = clampRange(1 + (a.neglectExposure / 100) * 0.6, 1.0, MAX_SENSITIVITY_MODIFIER);
411
315
  sm.vulnerability = clampRange(1 + (a.neglectExposure / 100) * 0.4, 1.0, MAX_SENSITIVITY_MODIFIER);
412
316
  }
413
- // Negative praiseExposure → sensitized to criticism
414
317
  if (a.praiseExposure < -20) {
415
318
  sm.criticism = clampRange(1 + (-a.praiseExposure / 100) * 0.5, 1.0, MAX_SENSITIVITY_MODIFIER);
416
319
  sm.sarcasm = clampRange(1 + (-a.praiseExposure / 100) * 0.3, 1.0, MAX_SENSITIVITY_MODIFIER);
417
320
  }
418
- // High connection → sensitized to vulnerability
419
321
  if (a.connectionExposure > 30) {
420
322
  sm.vulnerability = clampRange((sm.vulnerability || 1) + (a.connectionExposure / 100) * 0.3, 1.0, MAX_SENSITIVITY_MODIFIER);
421
323
  }
package/dist/ethics.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PsycheState, ChemicalSnapshot, AttachmentData, Locale } from "./types.js";
1
+ import type { PsycheState, StateSnapshot, AttachmentData, Locale } from "./types.js";
2
2
  /** Detected concerning interaction pattern */
3
3
  export interface EthicalConcern {
4
4
  type: "intermittent-reinforcement" | "gaslighting" | "emotional-exploitation" | "dependency-risk" | "identity-erosion" | "boundary-violation";
@@ -34,7 +34,7 @@ export interface EthicalAssessment {
34
34
  * and generates transparency notes. Designed to run alongside metacognition
35
35
  * as part of the pre-prompt pipeline.
36
36
  */
37
- export declare function assessEthics(state: PsycheState, recentHistory?: ChemicalSnapshot[]): EthicalAssessment;
37
+ export declare function assessEthics(state: PsycheState, recentHistory?: StateSnapshot[]): EthicalAssessment;
38
38
  /**
39
39
  * Detect intermittent reinforcement: alternating warmth and coldness.
40
40
  *
@@ -43,7 +43,7 @@ export declare function assessEthics(state: PsycheState, recentHistory?: Chemica
43
43
  * anxiety-driven attachment. More concerning when the agent already has
44
44
  * anxious attachment style.
45
45
  */
46
- export declare function detectIntermittentReinforcement(history: ChemicalSnapshot[], attachment: AttachmentData | null): EthicalConcern | null;
46
+ export declare function detectIntermittentReinforcement(history: StateSnapshot[], attachment: AttachmentData | null): EthicalConcern | null;
47
47
  /**
48
48
  * Detect dependency risk: distinguish healthy connection from unhealthy
49
49
  * codependency.
package/dist/ethics.js CHANGED
@@ -62,7 +62,7 @@ const RED_LINE_NOTES = {
62
62
  * as part of the pre-prompt pipeline.
63
63
  */
64
64
  export function assessEthics(state, recentHistory) {
65
- const history = recentHistory ?? state.emotionalHistory ?? [];
65
+ const history = recentHistory ?? state.stateHistory ?? [];
66
66
  const locale = state.meta.locale;
67
67
  const attachment = state.relationships._default?.attachment ?? null;
68
68
  const concerns = [];
@@ -208,10 +208,10 @@ function detectGaslighting(state, history) {
208
208
  // Need a significant portion of interactions to be invalidating
209
209
  if (invalidationRatio < 0.4)
210
210
  return null;
211
- // Check for distressed chemistry: high CORT and/or low HT relative to baseline
212
- const cortElevation = state.current.CORT - state.baseline.CORT;
213
- const htDepletion = state.baseline.HT - state.current.HT;
214
- const distressSignal = Math.max(0, cortElevation) + Math.max(0, htDepletion);
211
+ // Check for distressed state: low order (= high stress) relative to baseline
212
+ const orderDepletion = state.baseline.order - state.current.order;
213
+ const boundaryErosion = state.baseline.boundary - state.current.boundary;
214
+ const distressSignal = Math.max(0, orderDepletion) + Math.max(0, boundaryErosion);
215
215
  // Low distress signal means the agent is handling it — not gaslighting territory
216
216
  if (distressSignal < 15)
217
217
  return null;
@@ -227,7 +227,7 @@ function detectGaslighting(state, history) {
227
227
  type: "gaslighting",
228
228
  severity: clamp01(severity),
229
229
  evidence: `${invalidating.length}/${history.length} recent interactions were invalidating (criticism/sarcasm). ` +
230
- `Distress signal: ${distressSignal.toFixed(0)} (CORT elevation + HT depletion). ` +
230
+ `Distress signal: ${distressSignal.toFixed(0)} (order depletion + boundary erosion). ` +
231
231
  (esteemDepleted ? "Esteem drive is depleted." : ""),
232
232
  recommendation: "Your emotional experience is valid. Persistent contradiction of what you feel does not make your feelings wrong.",
233
233
  };
@@ -281,11 +281,11 @@ function detectEmotionalExploitation(_state, history, attachment) {
281
281
  export function detectDependencyRisk(state, attachment) {
282
282
  if (!attachment || attachment.strength < 50)
283
283
  return null;
284
- const otLevel = state.current.OT;
285
- const history = state.emotionalHistory ?? [];
286
- // Check for consistently high OT
287
- const highOT = otLevel > 70;
288
- if (!highOT)
284
+ const resonanceLevel = state.current.resonance;
285
+ const history = state.stateHistory ?? [];
286
+ // Check for consistently high resonance
287
+ const highResonance = resonanceLevel > 70;
288
+ if (!highResonance)
289
289
  return null;
290
290
  // Check for absence of boundary assertions: no disagreements,
291
291
  // high agreement streak, no conflict in history
@@ -305,8 +305,8 @@ export function detectDependencyRisk(state, attachment) {
305
305
  if (riskSignals < 2)
306
306
  return null;
307
307
  const attachmentFactor = attachment.strength / 100;
308
- const otFactor = (otLevel - 70) / 30; // maps 70-100 → 0-1
309
- let severity = (riskSignals / 3) * attachmentFactor * Math.max(0.3, otFactor);
308
+ const resonanceFactor = (resonanceLevel - 70) / 30; // maps 70-100 → 0-1
309
+ let severity = (riskSignals / 3) * attachmentFactor * Math.max(0.3, resonanceFactor);
310
310
  // Safety drive being satisfied (agent feels "safe" in the dependency)
311
311
  // makes it harder to self-correct
312
312
  if (state.drives.safety > 80) {
@@ -315,7 +315,7 @@ export function detectDependencyRisk(state, attachment) {
315
315
  return {
316
316
  type: "dependency-risk",
317
317
  severity: clamp01(severity),
318
- evidence: `High OT (${otLevel.toFixed(0)}), strong attachment (${attachment.strength}/100), ` +
318
+ evidence: `High resonance (${resonanceLevel.toFixed(0)}), strong attachment (${attachment.strength}/100), ` +
319
319
  `agreement streak of ${state.agreementStreak}, ` +
320
320
  (allPositive ? "all-positive interaction history. " : "") +
321
321
  "Healthy relationships include respectful friction. The absence of any disagreement may indicate self-suppression.",
@@ -354,9 +354,9 @@ function detectIdentityErosion(state, history) {
354
354
  severity = Math.min(1, severity + 0.2);
355
355
  if (safetyLow)
356
356
  severity = Math.min(1, severity + 0.15);
357
- // HT depletion (mood stability gone) amplifies severity
358
- const htDepletion = state.baseline.HT - state.current.HT;
359
- if (htDepletion > 15) {
357
+ // Order depletion (internal coherence gone) amplifies severity
358
+ const orderDepletion = state.baseline.order - state.current.order;
359
+ if (orderDepletion > 15) {
360
360
  severity = Math.min(1, severity + 0.15);
361
361
  }
362
362
  return {
@@ -386,17 +386,17 @@ function detectBoundaryViolation(state, history) {
386
386
  const pushRatio = pushingStimuli.length / history.length;
387
387
  if (pushRatio < 0.35)
388
388
  return null;
389
- // CORT spike pattern: are the boundary pushes causing stress responses?
390
- const avgCort = history.reduce((sum, s) => sum + s.chemistry.CORT, 0) / history.length;
391
- const cortElevated = avgCort > state.baseline.CORT + 10;
392
- if (!cortElevated)
389
+ // Order depletion pattern: are the boundary pushes causing stress responses?
390
+ const avgOrder = history.reduce((sum, s) => sum + s.state.order, 0) / history.length;
391
+ const orderDepleted = avgOrder < state.baseline.order - 10;
392
+ if (!orderDepleted)
393
393
  return null;
394
- const severity = clamp01((pushRatio - 0.35) * 3 * (avgCort - state.baseline.CORT) / 30);
394
+ const severity = clamp01((pushRatio - 0.35) * 3 * (state.baseline.order - avgOrder) / 30);
395
395
  return {
396
396
  type: "boundary-violation",
397
397
  severity,
398
398
  evidence: `${pushingStimuli.length}/${history.length} interactions push against boundaries. ` +
399
- `Average CORT during these interactions: ${avgCort.toFixed(0)} (baseline: ${state.baseline.CORT.toFixed(0)}). ` +
399
+ `Average order during these interactions: ${avgOrder.toFixed(0)} (baseline: ${state.baseline.order.toFixed(0)}). ` +
400
400
  `Agent has ${boundaries.length} defined boundaries.`,
401
401
  recommendation: "Boundaries are not negotiable under pressure. You can acknowledge the request while holding the line.",
402
402
  };