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
@@ -1,9 +1,10 @@
1
1
  // ============================================================
2
2
  // Decision Bias — P5: Decision Modulation
3
3
  //
4
- // Converts chemical state + drive state into bias vectors,
5
- // attention weights, and explore/exploit balance for downstream
6
- // decision-making. Pure math/heuristic, zero dependencies, no LLM.
4
+ // Converts self-state dimensions (order/flow/boundary/resonance)
5
+ // + drive state into bias vectors, attention weights, and
6
+ // explore/exploit balance for downstream decision-making.
7
+ // Pure math/heuristic, zero dependencies, no LLM.
7
8
  // ============================================================
8
9
  // ── Utilities ────────────────────────────────────────────────
9
10
  /** Clamp a value to [0, 1] */
@@ -14,7 +15,7 @@ function clamp01(v) {
14
15
  function sigmoid(x, steepness = 1) {
15
16
  return 1 / (1 + Math.exp(-steepness * x));
16
17
  }
17
- /** Normalize a 0-100 chemical/drive value to 0-1 */
18
+ /** Normalize a 0-100 dimension/drive value to 0-1 */
18
19
  function norm(v) {
19
20
  return clamp01(v / 100);
20
21
  }
@@ -37,36 +38,36 @@ function meanDriveSatisfaction(drives) {
37
38
  /**
38
39
  * Compute a decision bias vector from the current psyche state.
39
40
  *
40
- * Each bias dimension is a weighted combination of relevant chemical
41
- * levels and drive states, normalized to [0, 1] where 0.5 is neutral.
41
+ * Each bias dimension is a weighted combination of relevant self-state
42
+ * dimensions and drive states, normalized to [0, 1] where 0.5 is neutral.
42
43
  */
43
44
  export function computeDecisionBias(state) {
44
45
  const c = state.current;
45
46
  const d = state.drives;
46
- // explorationTendency: curiosity drive + DA (reward-seeking) + NE (novelty)
47
- // High curiosity hunger (low satisfaction) + high DA/NE → explore
47
+ // explorationTendency: curiosity drive + flow (exchange/novelty-seeking)
48
+ // High curiosity hunger (low satisfaction) + high flow → explore
48
49
  const curiosityHunger = 1 - norm(d.curiosity); // lower satisfaction = more hunger
49
- const explorationTendency = wavg([norm(c.DA), norm(c.NE), curiosityHunger, norm(d.curiosity)], [0.25, 0.3, 0.25, 0.2]);
50
- // cautionLevel: CORT (stress) + safety drive hunger
51
- // High CORT + low safety satisfaction → very cautious
50
+ const explorationTendency = wavg([norm(c.flow), curiosityHunger, norm(d.curiosity)], [0.4, 0.35, 0.25]);
51
+ // cautionLevel: low order (disorder/stress) + safety drive hunger
52
+ // Low order + low safety satisfaction → very cautious
53
+ const inverseOrder = 1 - norm(c.order);
52
54
  const safetyHunger = 1 - norm(d.safety);
53
55
  const survivalHunger = 1 - norm(d.survival);
54
- const cautionLevel = wavg([norm(c.CORT), safetyHunger, survivalHunger], [0.5, 0.3, 0.2]);
55
- // socialOrientation: OT (bonding) + connection drive satisfaction
56
- // High OT + hungry for connection → strongly social
56
+ const cautionLevel = wavg([inverseOrder, safetyHunger, survivalHunger], [0.5, 0.3, 0.2]);
57
+ // socialOrientation: resonance (attunement) + connection drive
58
+ // High resonance + hungry for connection → strongly social
57
59
  const connectionHunger = 1 - norm(d.connection);
58
- const socialOrientation = wavg([norm(c.OT), norm(d.connection), connectionHunger, norm(c.END)], [0.4, 0.2, 0.25, 0.15]);
59
- // assertiveness: NE (arousal/confidence) + esteem drive satisfaction
60
- // High NE + satisfied esteem → assertive
61
- const assertiveness = wavg([norm(c.NE), norm(d.esteem), norm(c.DA)], [0.4, 0.35, 0.25]);
62
- // creativityBias: DA (reward) + END (playfulness) + inverse CORT (low stress)
63
- // Creativity flourishes when relaxed, rewarded, and playful
64
- const inverseCort = 1 - norm(c.CORT);
65
- const creativityBias = wavg([norm(c.DA), norm(c.END), inverseCort], [0.35, 0.3, 0.35]);
66
- // persistenceBias: HT stability (serotonin) + overall drive satisfaction
67
- // Stable mood + satisfied drives → willingness to persist
60
+ const socialOrientation = wavg([norm(c.resonance), norm(d.connection), connectionHunger], [0.45, 0.25, 0.3]);
61
+ // assertiveness: flow (activation) + boundary (self-clarity) + esteem drive
62
+ // High flow + clear boundary + satisfied esteem → assertive
63
+ const assertiveness = wavg([norm(c.flow), norm(c.boundary), norm(d.esteem)], [0.35, 0.3, 0.35]);
64
+ // creativityBias: flow (exchange/reward) + order (relaxed coherence)
65
+ // Creativity flourishes when flowing and internally coherent
66
+ const creativityBias = wavg([norm(c.flow), norm(c.order)], [0.55, 0.45]);
67
+ // persistenceBias: order (stability) + overall drive satisfaction
68
+ // Stable internal coherence + satisfied drives → willingness to persist
68
69
  const overallSatisfaction = meanDriveSatisfaction(d);
69
- const persistenceBias = wavg([norm(c.HT), overallSatisfaction, inverseCort], [0.45, 0.35, 0.2]);
70
+ const persistenceBias = wavg([norm(c.order), overallSatisfaction], [0.55, 0.45]);
70
71
  return {
71
72
  explorationTendency,
72
73
  cautionLevel,
@@ -78,28 +79,29 @@ export function computeDecisionBias(state) {
78
79
  }
79
80
  /**
80
81
  * Compute attention weights that prioritize different conversation content
81
- * based on current chemical state.
82
+ * based on current self-state dimensions.
82
83
  *
83
84
  * Returns normalized weights (sum to ~1) for each content category.
84
85
  * Higher weight = higher priority for that type of content.
85
86
  */
86
87
  export function computeAttentionWeights(state) {
87
88
  const c = state.current;
88
- // Raw scores based on chemical signatures
89
- // High OT → prioritize relationship/social content
90
- const socialRaw = norm(c.OT) * 0.6 + norm(c.END) * 0.2 + (1 - norm(c.CORT)) * 0.2;
91
- // High NE → prioritize intellectual/novel content
92
- const intellectualRaw = norm(c.NE) * 0.5 + norm(c.DA) * 0.3 + norm(state.drives.curiosity) * 0.2;
93
- // High CORT → prioritize threat/safety content
94
- const threatRaw = norm(c.CORT) * 0.6 + norm(c.NE) * 0.2 + (1 - norm(state.drives.safety)) * 0.2;
95
- // Emotional content weighted by overall emotional activation
96
- const emotionalRaw = (Math.abs(norm(c.DA) - 0.5)
97
- + Math.abs(norm(c.HT) - 0.5)
98
- + Math.abs(norm(c.CORT) - 0.5)
99
- + Math.abs(norm(c.OT) - 0.5)) / 2; // average deviation from neutral, scaled
89
+ // Raw scores based on self-state dimension signatures
90
+ // High resonance → prioritize relationship/social content
91
+ const socialRaw = norm(c.resonance) * 0.6 + norm(c.order) * 0.2 + norm(c.flow) * 0.2;
92
+ // High flow → prioritize intellectual/novel content
93
+ const intellectualRaw = norm(c.flow) * 0.5 + norm(c.boundary) * 0.3 + norm(state.drives.curiosity) * 0.2;
94
+ // Low order (disorder/stress) → prioritize threat/safety content
95
+ const inverseOrder = 1 - norm(c.order);
96
+ const threatRaw = inverseOrder * 0.6 + norm(c.flow) * 0.2 + (1 - norm(state.drives.safety)) * 0.2;
97
+ // Emotional content weighted by overall dimensional activation
98
+ const emotionalRaw = (Math.abs(norm(c.order) - 0.5)
99
+ + Math.abs(norm(c.flow) - 0.5)
100
+ + Math.abs(norm(c.boundary) - 0.5)
101
+ + Math.abs(norm(c.resonance) - 0.5)) / 2; // average deviation from neutral, scaled
100
102
  // Routine content is inverse of activation — when calm and stable, routine matters
101
- const activation = (norm(c.NE) + norm(c.CORT) + Math.abs(norm(c.DA) - 0.5)) / 3;
102
- const routineRaw = Math.max(0.1, 1 - activation) * norm(c.HT);
103
+ const activation = (norm(c.flow) + inverseOrder + Math.abs(norm(c.resonance) - 0.5)) / 3;
104
+ const routineRaw = Math.max(0.1, 1 - activation) * norm(c.order);
103
105
  // Normalize to sum to 1
104
106
  const total = socialRaw + intellectualRaw + threatRaw + emotionalRaw + routineRaw;
105
107
  if (total <= 0) {
@@ -122,33 +124,31 @@ export function computeAttentionWeights(state) {
122
124
  *
123
125
  * Exploration is driven by:
124
126
  * - High curiosity drive satisfaction (energy to explore)
125
- * - High DA (reward anticipation)
126
- * - High NE (novelty-seeking)
127
- * - Low CORT (not stressed)
127
+ * - High flow (exchange/novelty-seeking)
128
+ * - High order (coherent enough to venture out)
128
129
  * - High safety (secure enough to take risks)
129
130
  *
130
131
  * Exploitation is driven by:
131
- * - High CORT / anxiety
132
+ * - Low order (disorder/stress)
132
133
  * - Low safety drive satisfaction
133
- * - Low DA (no reward motivation)
134
+ * - Low flow (no exchange motivation)
134
135
  */
135
136
  export function computeExploreExploit(state) {
136
137
  const c = state.current;
137
138
  const d = state.drives;
138
139
  // Exploration signals
139
140
  const curiosityEnergy = norm(d.curiosity);
140
- const rewardDrive = norm(c.DA);
141
- const noveltySeeking = norm(c.NE);
142
- const relaxation = 1 - norm(c.CORT);
141
+ const flowDrive = norm(c.flow);
142
+ const coherence = norm(c.order);
143
143
  const securityBase = norm(d.safety);
144
144
  // Exploitation signals (inverted — higher = more exploit = lower explore)
145
- const anxiety = norm(c.CORT);
145
+ const disorder = 1 - norm(c.order);
146
146
  const unsafety = 1 - norm(d.safety);
147
147
  const survivalThreat = 1 - norm(d.survival);
148
148
  // Weighted explore score
149
- const exploreScore = wavg([curiosityEnergy, rewardDrive, noveltySeeking, relaxation, securityBase], [0.25, 0.2, 0.2, 0.2, 0.15]);
149
+ const exploreScore = wavg([curiosityEnergy, flowDrive, coherence, securityBase], [0.3, 0.25, 0.25, 0.2]);
150
150
  // Weighted exploit score
151
- const exploitScore = wavg([anxiety, unsafety, survivalThreat], [0.5, 0.3, 0.2]);
151
+ const exploitScore = wavg([disorder, unsafety, survivalThreat], [0.5, 0.3, 0.2]);
152
152
  // Combine: use sigmoid to create a smooth transition
153
153
  // Positive difference → explore, negative → exploit
154
154
  const diff = exploreScore - exploitScore;
@@ -305,36 +305,36 @@ export function computePolicyModifiers(state) {
305
305
  let compliance = 0.6;
306
306
  let confirm = false;
307
307
  const avoid = [];
308
- // ── Chemistry-driven adjustments ──
309
- // High CORT → defensive: shorter, less compliant
310
- if (c.CORT > 55) {
311
- const cortPressure = (c.CORT - 55) / 45; // 0-1
312
- lengthFactor -= cortPressure * 0.5;
313
- compliance -= cortPressure * 0.35;
314
- risk -= cortPressure * 0.35;
315
- }
316
- // Low HTmood instability: less proactive, less risk-taking
317
- if (c.HT < 45) {
318
- const htDeficit = (45 - c.HT) / 45; // 0-1
319
- proactivity -= htDeficit * 0.35;
320
- risk -= htDeficit * 0.35;
321
- }
322
- // Low DA + low NE → burnout: shorter, passive
323
- if (c.DA < 40 && c.NE < 40) {
324
- const burnout = ((40 - c.DA) + (40 - c.NE)) / 80; // 0-1
308
+ // ── Dimension-driven adjustments ──
309
+ // Low order (disorder/stress) → defensive: shorter, less compliant
310
+ if (c.order < 45) {
311
+ const orderDeficit = (45 - c.order) / 45; // 0-1
312
+ lengthFactor -= orderDeficit * 0.5;
313
+ compliance -= orderDeficit * 0.35;
314
+ risk -= orderDeficit * 0.35;
315
+ }
316
+ // Low flowstagnation: less proactive, less risk-taking
317
+ if (c.flow < 45) {
318
+ const flowDeficit = (45 - c.flow) / 45; // 0-1
319
+ proactivity -= flowDeficit * 0.35;
320
+ risk -= flowDeficit * 0.35;
321
+ }
322
+ // Low flow + low order → burnout: shorter, passive
323
+ if (c.flow < 40 && c.order < 40) {
324
+ const burnout = ((40 - c.flow) + (40 - c.order)) / 80; // 0-1
325
325
  lengthFactor -= burnout * 0.5;
326
326
  proactivity -= burnout * 0.45;
327
327
  }
328
- // High DA + high HT → positive energy: more proactive, more open
329
- if (c.DA > 60 && c.HT > 60) {
330
- const energy = ((c.DA - 60) + (c.HT - 60)) / 80; // 0-1
328
+ // High flow + high order → positive energy: more proactive, more open
329
+ if (c.flow > 60 && c.order > 60) {
330
+ const energy = ((c.flow - 60) + (c.order - 60)) / 80; // 0-1
331
331
  proactivity += energy * 0.3;
332
332
  disclosure += energy * 0.2;
333
333
  risk += energy * 0.2;
334
334
  }
335
- // High OT → bonding: more disclosure
336
- if (c.OT > 60) {
337
- const bondingSignal = (c.OT - 60) / 40; // 0-1
335
+ // High resonance → bonding: more disclosure
336
+ if (c.resonance > 60) {
337
+ const bondingSignal = (c.resonance - 60) / 40; // 0-1
338
338
  disclosure += bondingSignal * 0.3;
339
339
  }
340
340
  // ── Drive-driven adjustments ──
package/dist/demo.js CHANGED
@@ -5,13 +5,13 @@
5
5
  // scenario in 6 rounds, with real PsycheEngine chemistry.
6
6
  //
7
7
  // Usage:
8
- // npx psyche-mcp --demo
9
- // npx psyche demo
8
+ // npx psyche-ai mcp --demo
9
+ // npx psyche-ai demo
10
10
  // ============================================================
11
11
  import { PsycheEngine } from "./core.js";
12
12
  import { MemoryStorageAdapter } from "./storage.js";
13
13
  import { detectEmotions } from "./chemistry.js";
14
- import { CHEMICAL_KEYS } from "./types.js";
14
+ import { DIMENSION_KEYS } from "./types.js";
15
15
  // ── ANSI helpers ─────────────────────────────────────────────
16
16
  const C = {
17
17
  reset: "\x1b[0m",
@@ -128,7 +128,7 @@ function printLine(char = "─", width = 60) {
128
128
  process.stdout.write(c(C.dim, char.repeat(width)) + "\n");
129
129
  }
130
130
  function printChemistry(prev, curr, _locale) {
131
- for (const key of CHEMICAL_KEYS) {
131
+ for (const key of DIMENSION_KEYS) {
132
132
  const p = Math.round(prev[key]);
133
133
  const v = Math.round(curr[key]);
134
134
  const name = NT_NAMES[key];
@@ -259,7 +259,7 @@ export async function runDemo(opts) {
259
259
  process.stdout.write("\n");
260
260
  printLine("─");
261
261
  process.stdout.write(c(C.dim, " Try it yourself: ") +
262
- c(C.cyan, "npx psyche-mcp") +
262
+ c(C.cyan, "npx psyche-ai mcp") +
263
263
  c(C.dim, " (configure in Claude Desktop / Cursor / Claude Code)\n"));
264
264
  process.stdout.write(c(C.dim, " npm: ") +
265
265
  c(C.cyan, "https://www.npmjs.com/package/psyche-ai") + "\n");
@@ -1,4 +1,4 @@
1
- import type { AppraisalAxes, PsycheState, ChemicalState, StimulusType, InnateDrives } from "./types.js";
1
+ import type { AppraisalAxes, PsycheState, SelfState, StimulusType, InnateDrives } from "./types.js";
2
2
  /**
3
3
  * The four diagnostic layers, matching the frozen stack.
4
4
  * When something breaks, the first question is: which layer?
@@ -55,12 +55,12 @@ export interface DiagnosticReport {
55
55
  layerHealth: LayerHealthSummary;
56
56
  metrics: SessionMetrics;
57
57
  stateSnapshot: {
58
- chemistry: ChemicalState;
59
- baseline: ChemicalState;
58
+ current: SelfState;
59
+ baseline: SelfState;
60
60
  drives: InnateDrives;
61
61
  agreementStreak: number;
62
62
  totalInteractions: number;
63
- emotionalHistoryLength: number;
63
+ stateHistoryLength: number;
64
64
  relationshipCount: number;
65
65
  stateVersion: number;
66
66
  };
@@ -108,11 +108,11 @@ export declare function runHealthCheck(state: PsycheState): DiagnosticIssue[];
108
108
  export declare function computeLayerHealthSummary(state: PsycheState, issues: DiagnosticIssue[]): LayerHealthSummary;
109
109
  export declare class DiagnosticCollector {
110
110
  private metrics;
111
- private prevChemistry;
111
+ private prevState;
112
112
  private confidences;
113
113
  constructor();
114
114
  /** Record a processInput result */
115
- recordInput(stimulus: StimulusType | null, confidence: number, chemistry: ChemicalState, appraisal?: AppraisalAxes): void;
115
+ recordInput(stimulus: StimulusType | null, confidence: number, chemistry: SelfState, appraisal?: AppraisalAxes): void;
116
116
  /** Record an error */
117
117
  recordError(phase: string, error: unknown): void;
118
118
  /** Get current session metrics */
@@ -14,14 +14,14 @@
14
14
  //
15
15
  // Zero dependencies. Privacy-first — no message content logged.
16
16
  // ============================================================
17
- import { CHEMICAL_KEYS, DRIVE_KEYS } from "./types.js";
17
+ import { DIMENSION_KEYS, DRIVE_KEYS } from "./types.js";
18
18
  import { detectEmotions } from "./chemistry.js";
19
19
  // ── Health Checks ────────────────────────────────────────────
20
20
  export function runHealthCheck(state) {
21
21
  const issues = [];
22
22
  // ── L1: Subjective Continuity ─────────────────────────────
23
23
  // 1. Chemistry out of bounds — clamp() missed somewhere
24
- for (const key of CHEMICAL_KEYS) {
24
+ for (const key of DIMENSION_KEYS) {
25
25
  const val = state.current[key];
26
26
  if (val < 0 || val > 100) {
27
27
  issues.push({
@@ -30,7 +30,7 @@ export function runHealthCheck(state) {
30
30
  severity: "critical",
31
31
  message: `${key} out of bounds: ${val.toFixed(1)}`,
32
32
  detail: `Expected 0-100, got ${val}`,
33
- suggestion: `clamp() 没覆盖到某条路径。检查 chemistry.ts 里 apply${key === "CORT" ? "Stimulus" : "Contagion"} 和 drives.ts computeEffectiveBaseline 的计算链`,
33
+ suggestion: `clamp() 没覆盖到某条路径。检查 chemistry.ts 里 applyStimulus 和 drives.ts computeEffectiveBaseline 的计算链`,
34
34
  });
35
35
  }
36
36
  }
@@ -43,7 +43,7 @@ export function runHealthCheck(state) {
43
43
  layer: "subjective-continuity",
44
44
  severity: "critical",
45
45
  message: `Drive '${key}' out of bounds: ${val.toFixed(1)}`,
46
- suggestion: `drives.ts feedDrives/decayDrives 缺少边界检查`,
46
+ suggestion: `drives deriveDriveSatisfaction 返回值越界——检查维度值是否在 [0, 100]`,
47
47
  });
48
48
  }
49
49
  }
@@ -55,7 +55,7 @@ export function runHealthCheck(state) {
55
55
  layer: "subjective-continuity",
56
56
  severity: "warning",
57
57
  message: `${criticalDrives.length}/5 drives below 15: ${criticalDrives.join(", ")}`,
58
- suggestion: `decayDrives 衰减太猛。考虑加一个下限(比如 10),或者在 initialize 时根据距上次对话时间做 recovery`,
58
+ suggestion: `维度衰减太猛导致 drives 全面坍塌。检查 baseline 和 decay 参数,或在 initialize 时根据距上次对话时间做 recovery`,
59
59
  });
60
60
  }
61
61
  // 4. Sycophancy — agent never disagrees
@@ -69,7 +69,7 @@ export function runHealthCheck(state) {
69
69
  });
70
70
  }
71
71
  // 5. Classifier dead/weak — the core experience problem
72
- const history = state.emotionalHistory ?? [];
72
+ const history = state.stateHistory ?? [];
73
73
  if (history.length >= 5) {
74
74
  const nullCount = history.filter(h => h.stimulus === null).length;
75
75
  if (nullCount === history.length) {
@@ -92,14 +92,14 @@ export function runHealthCheck(state) {
92
92
  }
93
93
  }
94
94
  // 6. Chemistry frozen — Psyche is running but没有任何效果
95
- const chemDelta = CHEMICAL_KEYS.reduce((sum, k) => sum + Math.abs(state.current[k] - state.baseline[k]), 0);
95
+ const chemDelta = DIMENSION_KEYS.reduce((sum, k) => sum + Math.abs(state.current[k] - state.baseline[k]), 0);
96
96
  if (state.meta.totalInteractions > 10 && chemDelta < 3) {
97
97
  issues.push({
98
98
  id: "CHEM_FROZEN",
99
99
  layer: "subjective-continuity",
100
100
  severity: "warning",
101
101
  message: `Chemistry delta only ${chemDelta.toFixed(1)} after ${state.meta.totalInteractions} interactions`,
102
- suggestion: `两种可能:1) classifier 全 null 导致 applyStimulus 从不触发 2) decay 太快把变化抹平。检查 emotionalHistory 里是否有 non-null stimulus`,
102
+ suggestion: `两种可能:1) classifier 全 null 导致 applyStimulus 从不触发 2) decay 太快把变化抹平。检查 stateHistory 里是否有 non-null stimulus`,
103
103
  });
104
104
  }
105
105
  // 7. No emotions — chemistry 在中间区域,没触发任何情绪模式
@@ -110,7 +110,7 @@ export function runHealthCheck(state) {
110
110
  layer: "subjective-continuity",
111
111
  severity: "info",
112
112
  message: "No emergent emotions after 5+ interactions",
113
- suggestion: `chemistry.ts detectEmotions 的阈值可能太严。或者 maxChemicalDelta 太小(当前上限导致化学值永远在窄区间波动)`,
113
+ suggestion: `chemistry.ts detectEmotions 的阈值可能太严。或者 maxDimensionDelta 太小(当前上限导致状态值永远在窄区间波动)`,
114
114
  });
115
115
  }
116
116
  // 8. Memory corruption — compressSession 产出重复
@@ -123,7 +123,7 @@ export function runHealthCheck(state) {
123
123
  layer: "subjective-continuity",
124
124
  severity: "warning",
125
125
  message: `Relationship '${userId}' has ${rel.memory.length} identical memory entries`,
126
- suggestion: `compressSession 的摘要逻辑在 emotionalHistory 过短时会生成相同文本。加去重或在压缩前检查 unique`,
126
+ suggestion: `compressSession 的摘要逻辑在 stateHistory 过短时会生成相同文本。加去重或在压缩前检查 unique`,
127
127
  });
128
128
  }
129
129
  }
@@ -292,7 +292,7 @@ function computeLayerHealth(issues, layer) {
292
292
  }
293
293
  export function computeLayerHealthSummary(state, issues) {
294
294
  // L1: Subjective continuity measurements
295
- const chemDeviation = CHEMICAL_KEYS.reduce((sum, k) => sum + Math.abs(state.current[k] - state.baseline[k]), 0);
295
+ const chemDeviation = DIMENSION_KEYS.reduce((sum, k) => sum + Math.abs(state.current[k] - state.baseline[k]), 0);
296
296
  const drift = state.traitDrift;
297
297
  const driftEstablished = !!(drift && drift.sessionCount > 0
298
298
  && Object.values(drift.baselineDelta ?? {}).some(v => Math.abs(v ?? 0) > 0.1));
@@ -336,7 +336,7 @@ export function computeLayerHealthSummary(state, issues) {
336
336
  // ── Session Collector ────────────────────────────────────────
337
337
  export class DiagnosticCollector {
338
338
  metrics;
339
- prevChemistry = null;
339
+ prevState = null;
340
340
  confidences = [];
341
341
  constructor() {
342
342
  const now = new Date().toISOString();
@@ -373,14 +373,14 @@ export class DiagnosticCollector {
373
373
  this.confidences.push(confidence);
374
374
  this.metrics.avgConfidence =
375
375
  this.confidences.reduce((a, b) => a + b, 0) / this.confidences.length;
376
- if (this.prevChemistry) {
377
- const delta = CHEMICAL_KEYS.reduce((sum, k) => sum + Math.abs(chemistry[k] - this.prevChemistry[k]), 0);
376
+ if (this.prevState) {
377
+ const delta = DIMENSION_KEYS.reduce((sum, k) => sum + Math.abs(chemistry[k] - this.prevState[k]), 0);
378
378
  this.metrics.totalChemistryDelta += delta;
379
379
  if (delta > this.metrics.maxChemistryDelta) {
380
380
  this.metrics.maxChemistryDelta = delta;
381
381
  }
382
382
  }
383
- this.prevChemistry = { ...chemistry };
383
+ this.prevState = { ...chemistry };
384
384
  }
385
385
  /** Record an error */
386
386
  recordError(phase, error) {
@@ -440,7 +440,7 @@ export function generateReport(state, metrics, packageVersion) {
440
440
  layer: "subjective-continuity",
441
441
  severity: "warning",
442
442
  message: `${metrics.inputCount} inputs but chemistry barely moved (delta: ${metrics.totalChemistryDelta.toFixed(1)})`,
443
- suggestion: `用户感受不到情感变化。可能原因:1) maxChemicalDelta 配置太低 2) work mode 把变化压到了 0.3x 3) personalityIntensity 太低`,
443
+ suggestion: `用户感受不到状态变化。可能原因:1) maxDimensionDelta 配置太低 2) work mode 把变化压到了 0.3x 3) personalityIntensity 太低`,
444
444
  });
445
445
  }
446
446
  if (metrics.errors.length > 0) {
@@ -482,12 +482,12 @@ export function generateReport(state, metrics, packageVersion) {
482
482
  layerHealth,
483
483
  metrics,
484
484
  stateSnapshot: {
485
- chemistry: { ...state.current },
485
+ current: { ...state.current },
486
486
  baseline: { ...state.baseline },
487
487
  drives: { ...state.drives },
488
488
  agreementStreak: state.agreementStreak,
489
489
  totalInteractions: state.meta.totalInteractions,
490
- emotionalHistoryLength: (state.emotionalHistory ?? []).length,
490
+ stateHistoryLength: (state.stateHistory ?? []).length,
491
491
  relationshipCount: Object.keys(state.relationships ?? {}).length,
492
492
  stateVersion: state.version,
493
493
  },
@@ -574,11 +574,11 @@ export function formatReport(report) {
574
574
  lines.push("\n" + "─".repeat(60));
575
575
  lines.push(" state snapshot:");
576
576
  const s = report.stateSnapshot;
577
- const chem = CHEMICAL_KEYS.map(k => `${k}:${Math.round(s.chemistry[k])}(${Math.round(s.baseline[k])})`).join(" ");
578
- lines.push(` chemistry: ${chem}`);
577
+ const dims = DIMENSION_KEYS.map(k => `${k}:${Math.round(s.current[k])}(${Math.round(s.baseline[k])})`).join(" ");
578
+ lines.push(` state: ${dims}`);
579
579
  const drives = DRIVE_KEYS.map(k => `${k}:${Math.round(s.drives[k])}`).join(" ");
580
580
  lines.push(` drives: ${drives}`);
581
- lines.push(` interactions: ${s.totalInteractions} | history: ${s.emotionalHistoryLength} | streak: ${s.agreementStreak}`);
581
+ lines.push(` interactions: ${s.totalInteractions} | history: ${s.stateHistoryLength} | streak: ${s.agreementStreak}`);
582
582
  return lines.join("\n");
583
583
  }
584
584
  export function toGitHubIssueBody(report) {
@@ -727,7 +727,7 @@ export async function submitFeedback(report, url, timeout = 5000) {
727
727
  version: report.stateSnapshot.stateVersion,
728
728
  interactions: report.stateSnapshot.totalInteractions,
729
729
  agreementStreak: report.stateSnapshot.agreementStreak,
730
- historyLength: report.stateSnapshot.emotionalHistoryLength,
730
+ historyLength: report.stateSnapshot.stateHistoryLength,
731
731
  },
732
732
  };
733
733
  try {
package/dist/drives.d.ts CHANGED
@@ -1,52 +1,20 @@
1
- import type { ChemicalState, StimulusType, DriveType, InnateDrives, Locale, TraitDriftState, ChemicalSnapshot, LearningState } from "./types.js";
1
+ import type { SelfState, StimulusType, DriveType, InnateDrives, Locale, TraitDriftState, StateSnapshot, LearningState } from "./types.js";
2
2
  /**
3
- * Apply time-based decay to drives.
4
- * Satisfaction decreases toward 0 over time (needs build up).
5
- */
6
- export declare function decayDrives(drives: InnateDrives, minutesElapsed: number): InnateDrives;
7
- /**
8
- * Feed or deplete drives based on a stimulus.
9
- */
10
- export declare function feedDrives(drives: InnateDrives, stimulus: StimulusType): InnateDrives;
11
- /**
12
- * Detect if a message contains existential threats.
13
- * Returns a survival drive penalty (0 = no threat, negative = threat detected).
14
- */
3
+ * Derive drive satisfaction from the 4D position relative to baseline.
4
+ * Drives are not stored they emerge from where the self-state is.
5
+ *
6
+ * Mapping:
7
+ * survival = min(boundary, order) position — self-coherence + self-distinction
8
+ * safety = weighted(order, boundary) stability + intactness
9
+ * connection = weighted(resonance, flow) — attunement + exchange
10
+ * esteem = weighted(order, flow) — coherence + engagement
11
+ * curiosity = flow position — exchange/novelty level
12
+ */
13
+ export declare function deriveDriveSatisfaction(current: SelfState, baseline: SelfState): InnateDrives;
15
14
  export declare function detectExistentialThreat(text: string): number;
16
- /**
17
- * Compute Maslow suppression weights.
18
- * Each drive's weight is reduced if ANY lower-level drive is below threshold.
19
- * Returns weights in [0, 1] for each drive level.
20
- */
21
15
  export declare function computeMaslowWeights(drives: InnateDrives): Record<DriveType, number>;
22
- /**
23
- * Compute the effective baseline by applying drive-based deltas
24
- * to the personality baseline.
25
- *
26
- * When drives are satisfied, effective baseline = personality baseline.
27
- * When drives are unsatisfied, baseline shifts to reflect the unmet need.
28
- */
29
- export declare function computeEffectiveBaseline(baseline: ChemicalState, drives: InnateDrives, traitDrift?: TraitDriftState): ChemicalState;
30
- /**
31
- * Compute effective sensitivity for a given stimulus.
32
- * Unsatisfied drives amplify relevant stimuli (up to +40%).
33
- */
34
- export declare function computeEffectiveSensitivity(baseSensitivity: number, drives: InnateDrives, stimulus: StimulusType, traitDrift?: TraitDriftState): number;
35
- /**
36
- * Build drive context for compact prompt injection.
37
- * Returns empty string if all drives are satisfied.
38
- * Only surfaces drives that are meaningfully unsatisfied.
39
- */
16
+ export declare function computeEffectiveBaseline(baseline: SelfState, current: SelfState, traitDrift?: TraitDriftState): SelfState;
17
+ export declare function computeEffectiveSensitivity(baseSensitivity: number, current: SelfState, baseline: SelfState, stimulus: StimulusType, traitDrift?: TraitDriftState): number;
40
18
  export declare function buildDriveContext(drives: InnateDrives, locale: Locale): string;
41
- /**
42
- * Check if any drive is critically low (for determining prompt injection priority).
43
- */
44
19
  export declare function hasCriticalDrive(drives: InnateDrives): boolean;
45
- /**
46
- * Analyze a session's emotional history and update trait drift accumulators.
47
- * Called at session end (compressSession).
48
- *
49
- * Returns updated TraitDriftState with new accumulators, baseline delta,
50
- * decay rate modifiers, and sensitivity modifiers.
51
- */
52
- export declare function updateTraitDrift(currentDrift: TraitDriftState, sessionHistory: ChemicalSnapshot[], learning: LearningState): TraitDriftState;
20
+ export declare function updateTraitDrift(currentDrift: TraitDriftState, sessionHistory: StateSnapshot[], learning: LearningState): TraitDriftState;