psyche-ai 10.2.3 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -82
- package/dist/adapters/claude-sdk.d.ts +5 -5
- package/dist/adapters/claude-sdk.js +34 -32
- package/dist/adapters/mcp.js +4 -4
- package/dist/adapters/openclaw.js +12 -14
- package/dist/attachment.d.ts +3 -13
- package/dist/attachment.js +36 -88
- package/dist/autonomic.d.ts +4 -4
- package/dist/autonomic.js +28 -24
- package/dist/chemistry.d.ts +47 -21
- package/dist/chemistry.js +145 -91
- package/dist/circadian.d.ts +11 -43
- package/dist/circadian.js +24 -84
- package/dist/cli.js +37 -30
- package/dist/context-classifier.js +2 -2
- package/dist/core.d.ts +3 -3
- package/dist/core.js +99 -88
- package/dist/custom-profile.d.ts +20 -20
- package/dist/custom-profile.js +12 -12
- package/dist/decision-bias.d.ts +7 -8
- package/dist/decision-bias.js +74 -74
- package/dist/demo.js +5 -5
- package/dist/diagnostics.d.ts +6 -6
- package/dist/diagnostics.js +22 -22
- package/dist/drives.d.ts +15 -47
- package/dist/drives.js +98 -196
- package/dist/ethics.d.ts +3 -3
- package/dist/ethics.js +23 -23
- package/dist/experience.d.ts +34 -0
- package/dist/experience.js +200 -0
- package/dist/experiential-field.d.ts +19 -14
- package/dist/experiential-field.js +110 -100
- package/dist/generative-self.d.ts +5 -5
- package/dist/generative-self.js +124 -115
- package/dist/guards.d.ts +4 -4
- package/dist/guards.js +7 -7
- package/dist/i18n.js +61 -61
- package/dist/index.d.ts +8 -2
- package/dist/index.js +8 -1
- package/dist/input-turn.js +4 -6
- package/dist/interaction.d.ts +4 -4
- package/dist/interaction.js +10 -10
- package/dist/learning.d.ts +6 -6
- package/dist/learning.js +18 -18
- package/dist/metacognition.d.ts +2 -2
- package/dist/metacognition.js +79 -94
- package/dist/perceive.d.ts +44 -0
- package/dist/perceive.js +231 -0
- package/dist/primary-systems.d.ts +2 -2
- package/dist/primary-systems.js +21 -19
- package/dist/profiles.d.ts +5 -13
- package/dist/profiles.js +33 -51
- package/dist/prompt.d.ts +2 -2
- package/dist/prompt.js +51 -53
- package/dist/psyche-file.d.ts +7 -7
- package/dist/psyche-file.js +77 -78
- package/dist/relation-dynamics.d.ts +4 -0
- package/dist/relation-dynamics.js +1 -1
- package/dist/reply-envelope.d.ts +25 -1
- package/dist/reply-envelope.js +26 -11
- package/dist/self-recognition.d.ts +3 -3
- package/dist/self-recognition.js +17 -17
- package/dist/subjectivity.js +7 -7
- package/dist/temporal.d.ts +6 -6
- package/dist/temporal.js +37 -39
- package/dist/types.d.ts +67 -45
- package/dist/types.js +55 -51
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/decision-bias.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// ============================================================
|
|
2
2
|
// Decision Bias — P5: Decision Modulation
|
|
3
3
|
//
|
|
4
|
-
// Converts
|
|
5
|
-
// attention weights, and
|
|
6
|
-
//
|
|
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
|
|
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
|
|
41
|
-
*
|
|
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 +
|
|
47
|
-
// High curiosity hunger (low satisfaction) + high
|
|
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.
|
|
50
|
-
// cautionLevel:
|
|
51
|
-
//
|
|
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([
|
|
55
|
-
// socialOrientation:
|
|
56
|
-
// High
|
|
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.
|
|
59
|
-
// assertiveness:
|
|
60
|
-
// High
|
|
61
|
-
const assertiveness = wavg([norm(c.
|
|
62
|
-
// creativityBias:
|
|
63
|
-
// Creativity flourishes when
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
//
|
|
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.
|
|
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
|
|
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
|
|
89
|
-
// High
|
|
90
|
-
const socialRaw = norm(c.
|
|
91
|
-
// High
|
|
92
|
-
const intellectualRaw = norm(c.
|
|
93
|
-
//
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
+ Math.abs(norm(c.
|
|
99
|
-
+ Math.abs(norm(c.
|
|
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.
|
|
102
|
-
const routineRaw = Math.max(0.1, 1 - activation) * norm(c.
|
|
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
|
|
126
|
-
* - High
|
|
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
|
-
* -
|
|
132
|
+
* - Low order (disorder/stress)
|
|
132
133
|
* - Low safety drive satisfaction
|
|
133
|
-
* - Low
|
|
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
|
|
141
|
-
const
|
|
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
|
|
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,
|
|
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([
|
|
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
|
-
// ──
|
|
309
|
-
//
|
|
310
|
-
if (c.
|
|
311
|
-
const
|
|
312
|
-
lengthFactor -=
|
|
313
|
-
compliance -=
|
|
314
|
-
risk -=
|
|
315
|
-
}
|
|
316
|
-
// Low
|
|
317
|
-
if (c.
|
|
318
|
-
const
|
|
319
|
-
proactivity -=
|
|
320
|
-
risk -=
|
|
321
|
-
}
|
|
322
|
-
// Low
|
|
323
|
-
if (c.
|
|
324
|
-
const burnout = ((40 - c.
|
|
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 flow → stagnation: 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
|
|
329
|
-
if (c.
|
|
330
|
-
const energy = ((c.
|
|
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
|
|
336
|
-
if (c.
|
|
337
|
-
const bondingSignal = (c.
|
|
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 {
|
|
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
|
|
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");
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppraisalAxes, PsycheState,
|
|
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
|
-
|
|
59
|
-
baseline:
|
|
58
|
+
current: SelfState;
|
|
59
|
+
baseline: SelfState;
|
|
60
60
|
drives: InnateDrives;
|
|
61
61
|
agreementStreak: number;
|
|
62
62
|
totalInteractions: number;
|
|
63
|
-
|
|
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
|
|
111
|
+
private prevState;
|
|
112
112
|
private confidences;
|
|
113
113
|
constructor();
|
|
114
114
|
/** Record a processInput result */
|
|
115
|
-
recordInput(stimulus: StimulusType | null, confidence: number, chemistry:
|
|
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 */
|
package/dist/diagnostics.js
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
//
|
|
15
15
|
// Zero dependencies. Privacy-first — no message content logged.
|
|
16
16
|
// ============================================================
|
|
17
|
-
import {
|
|
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
|
|
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 里
|
|
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
|
|
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:
|
|
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.
|
|
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 =
|
|
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 太快把变化抹平。检查
|
|
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 的阈值可能太严。或者
|
|
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 的摘要逻辑在
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
377
|
-
const delta =
|
|
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.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
578
|
-
lines.push(`
|
|
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.
|
|
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.
|
|
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 {
|
|
1
|
+
import type { SelfState, StimulusType, DriveType, InnateDrives, Locale, TraitDriftState, StateSnapshot, LearningState } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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;
|