psyche-ai 7.1.0 → 9.0.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/dist/autonomic.d.ts +20 -2
- package/dist/autonomic.js +73 -20
- package/dist/chemistry.d.ts +2 -2
- package/dist/chemistry.js +19 -4
- package/dist/circadian.d.ts +19 -1
- package/dist/circadian.js +66 -0
- package/dist/core.d.ts +3 -1
- package/dist/core.js +105 -46
- package/dist/decision-bias.d.ts +13 -1
- package/dist/decision-bias.js +189 -0
- package/dist/drives.d.ts +11 -3
- package/dist/drives.js +181 -2
- package/dist/experiential-field.d.ts +25 -2
- package/dist/experiential-field.js +118 -125
- package/dist/index.d.ts +9 -8
- package/dist/index.js +11 -8
- package/dist/prompt.d.ts +2 -0
- package/dist/prompt.js +7 -0
- package/dist/psyche-file.d.ts +21 -1
- package/dist/psyche-file.js +113 -3
- package/dist/types.d.ts +81 -3
- package/dist/types.js +21 -2
- package/package.json +1 -1
package/dist/autonomic.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { ChemicalState, InnateDrives, Locale } from "./types.js";
|
|
1
|
+
import type { ChemicalState, InnateDrives, Locale, EnergyBudgets } from "./types.js";
|
|
2
2
|
export type AutonomicState = "ventral-vagal" | "sympathetic" | "dorsal-vagal";
|
|
3
3
|
export interface AutonomicResult {
|
|
4
4
|
state: AutonomicState;
|
|
5
5
|
transitionProgress: number;
|
|
6
6
|
gatedEmotionCategories: string[];
|
|
7
7
|
description: string;
|
|
8
|
+
processingDepth: number;
|
|
9
|
+
skippedStages: string[];
|
|
8
10
|
}
|
|
9
11
|
export interface AutonomicTransition {
|
|
10
12
|
from: AutonomicState;
|
|
@@ -32,10 +34,26 @@ export declare function getTransitionTime(from: AutonomicState, to: AutonomicSta
|
|
|
32
34
|
* Describe an autonomic state in the given locale.
|
|
33
35
|
*/
|
|
34
36
|
export declare function describeAutonomicState(state: AutonomicState, locale: Locale): string;
|
|
37
|
+
/**
|
|
38
|
+
* P10: Compute processing depth from autonomic state and chemistry.
|
|
39
|
+
*
|
|
40
|
+
* Processing depth represents the cognitive resource available for reflection:
|
|
41
|
+
* - 0 = pure System 1 (intuition only, no metacognition)
|
|
42
|
+
* - 1 = full System 2 (complete reflective capacity)
|
|
43
|
+
*
|
|
44
|
+
* This is a natural extension of autonomic state: you can't deeply reflect
|
|
45
|
+
* when your nervous system is in fight/flight/freeze mode.
|
|
46
|
+
*/
|
|
47
|
+
export declare function computeProcessingDepth(autonomicState: AutonomicState, chemistry: ChemicalState, baseline: ChemicalState, energyBudgets?: EnergyBudgets): {
|
|
48
|
+
depth: number;
|
|
49
|
+
skippedStages: string[];
|
|
50
|
+
};
|
|
35
51
|
/**
|
|
36
52
|
* Compute the full autonomic result with transition inertia.
|
|
37
53
|
*
|
|
38
54
|
* If previousState differs from the target state, transition progress
|
|
39
55
|
* is based on elapsed time vs required transition time.
|
|
56
|
+
*
|
|
57
|
+
* Includes P10 processing depth (dual-process cognitive gating).
|
|
40
58
|
*/
|
|
41
|
-
export declare function computeAutonomicResult(chemistry: ChemicalState, drives: InnateDrives, previousState: AutonomicState | null, minutesSinceLastUpdate: number, locale?: Locale): AutonomicResult;
|
|
59
|
+
export declare function computeAutonomicResult(chemistry: ChemicalState, drives: InnateDrives, previousState: AutonomicState | null, minutesSinceLastUpdate: number, locale?: Locale, baseline?: ChemicalState, energyBudgets?: EnergyBudgets): AutonomicResult;
|
package/dist/autonomic.js
CHANGED
|
@@ -121,22 +121,85 @@ export function getTransitionTime(from, to) {
|
|
|
121
121
|
export function describeAutonomicState(state, locale) {
|
|
122
122
|
return AUTONOMIC_STRINGS[locale]?.[state] ?? AUTONOMIC_STRINGS.zh[state];
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* P10: Compute processing depth from autonomic state and chemistry.
|
|
126
|
+
*
|
|
127
|
+
* Processing depth represents the cognitive resource available for reflection:
|
|
128
|
+
* - 0 = pure System 1 (intuition only, no metacognition)
|
|
129
|
+
* - 1 = full System 2 (complete reflective capacity)
|
|
130
|
+
*
|
|
131
|
+
* This is a natural extension of autonomic state: you can't deeply reflect
|
|
132
|
+
* when your nervous system is in fight/flight/freeze mode.
|
|
133
|
+
*/
|
|
134
|
+
export function computeProcessingDepth(autonomicState, chemistry, baseline, energyBudgets) {
|
|
135
|
+
const { DA, HT, CORT, OT, NE, END } = chemistry;
|
|
136
|
+
// Chemical deviation from baseline (0-1)
|
|
137
|
+
let totalDeviation = 0;
|
|
138
|
+
const keys = ["DA", "HT", "CORT", "OT", "NE", "END"];
|
|
139
|
+
for (const k of keys) {
|
|
140
|
+
totalDeviation += Math.abs(chemistry[k] - baseline[k]);
|
|
141
|
+
}
|
|
142
|
+
const chemDeviation = Math.min(1, totalDeviation / 600);
|
|
143
|
+
// Base depth from autonomic state
|
|
144
|
+
let baseDepth;
|
|
145
|
+
if (autonomicState === "dorsal-vagal") {
|
|
146
|
+
baseDepth = 0;
|
|
147
|
+
}
|
|
148
|
+
else if (autonomicState === "sympathetic") {
|
|
149
|
+
// Higher CORT in sympathetic = less cognitive resource
|
|
150
|
+
baseDepth = CORT >= 60 ? 0.15 : 0.35;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// ventral-vagal: safe, most cognitive resource available
|
|
154
|
+
baseDepth = 0.85;
|
|
155
|
+
}
|
|
156
|
+
// Chemical deviation reduces depth (strong emotions = less reflection)
|
|
157
|
+
let depth = Math.max(0, Math.min(1, baseDepth * (1 - chemDeviation * 0.5)));
|
|
158
|
+
// v9: Low attention energy further reduces processing depth
|
|
159
|
+
if (energyBudgets && energyBudgets.attention < 30) {
|
|
160
|
+
const attentionPenalty = (30 - energyBudgets.attention) / 30 * 0.3;
|
|
161
|
+
depth = Math.max(0, depth - attentionPenalty);
|
|
162
|
+
}
|
|
163
|
+
// Map depth to skipped pipeline stages
|
|
164
|
+
const skippedStages = [];
|
|
165
|
+
if (depth < 0.8)
|
|
166
|
+
skippedStages.push("generative-self");
|
|
167
|
+
if (depth < 0.5) {
|
|
168
|
+
skippedStages.push("ethics");
|
|
169
|
+
skippedStages.push("shared-intentionality");
|
|
170
|
+
}
|
|
171
|
+
if (depth < 0.2) {
|
|
172
|
+
skippedStages.push("metacognition");
|
|
173
|
+
skippedStages.push("experiential-field");
|
|
174
|
+
}
|
|
175
|
+
return { depth, skippedStages };
|
|
176
|
+
}
|
|
124
177
|
/**
|
|
125
178
|
* Compute the full autonomic result with transition inertia.
|
|
126
179
|
*
|
|
127
180
|
* If previousState differs from the target state, transition progress
|
|
128
181
|
* is based on elapsed time vs required transition time.
|
|
182
|
+
*
|
|
183
|
+
* Includes P10 processing depth (dual-process cognitive gating).
|
|
129
184
|
*/
|
|
130
|
-
export function computeAutonomicResult(chemistry, drives, previousState, minutesSinceLastUpdate, locale = "zh") {
|
|
185
|
+
export function computeAutonomicResult(chemistry, drives, previousState, minutesSinceLastUpdate, locale = "zh", baseline, energyBudgets) {
|
|
131
186
|
const targetState = computeAutonomicState(chemistry, drives);
|
|
132
|
-
|
|
133
|
-
|
|
187
|
+
const effectiveBaseline = baseline ?? { DA: 50, HT: 50, CORT: 50, OT: 50, NE: 50, END: 50 };
|
|
188
|
+
// Helper to build full result with processing depth
|
|
189
|
+
const buildResult = (state, transitionProgress) => {
|
|
190
|
+
const { depth, skippedStages } = computeProcessingDepth(state, chemistry, effectiveBaseline, energyBudgets);
|
|
134
191
|
return {
|
|
135
|
-
state
|
|
136
|
-
transitionProgress
|
|
137
|
-
gatedEmotionCategories: getGatedCategories(
|
|
138
|
-
description: describeAutonomicState(
|
|
192
|
+
state,
|
|
193
|
+
transitionProgress,
|
|
194
|
+
gatedEmotionCategories: getGatedCategories(state),
|
|
195
|
+
description: describeAutonomicState(state, locale),
|
|
196
|
+
processingDepth: depth,
|
|
197
|
+
skippedStages,
|
|
139
198
|
};
|
|
199
|
+
};
|
|
200
|
+
// First call or same state — immediate
|
|
201
|
+
if (previousState === null || previousState === targetState) {
|
|
202
|
+
return buildResult(targetState, 1);
|
|
140
203
|
}
|
|
141
204
|
// Transitioning between states
|
|
142
205
|
const transitionTime = getTransitionTime(previousState, targetState);
|
|
@@ -145,20 +208,10 @@ export function computeAutonomicResult(chemistry, drives, previousState, minutes
|
|
|
145
208
|
: Math.min(1, minutesSinceLastUpdate / transitionTime);
|
|
146
209
|
// If transition is complete, use the new state
|
|
147
210
|
if (progress >= 1) {
|
|
148
|
-
return
|
|
149
|
-
state: targetState,
|
|
150
|
-
transitionProgress: 1,
|
|
151
|
-
gatedEmotionCategories: getGatedCategories(targetState),
|
|
152
|
-
description: describeAutonomicState(targetState, locale),
|
|
153
|
-
};
|
|
211
|
+
return buildResult(targetState, 1);
|
|
154
212
|
}
|
|
155
|
-
// Transition in progress
|
|
156
|
-
return
|
|
157
|
-
state: targetState,
|
|
158
|
-
transitionProgress: progress,
|
|
159
|
-
gatedEmotionCategories: getGatedCategories(targetState),
|
|
160
|
-
description: describeAutonomicState(targetState, locale),
|
|
161
|
-
};
|
|
213
|
+
// Transition in progress
|
|
214
|
+
return buildResult(targetState, progress);
|
|
162
215
|
}
|
|
163
216
|
// ── Internal Helpers ─────────────────────────────────────────
|
|
164
217
|
/** Get the list of emotion categories that are blocked/gated for a state */
|
package/dist/chemistry.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare function clamp(v: number): number;
|
|
|
8
8
|
*
|
|
9
9
|
* decayed = baseline + (current - baseline) * factor^(minutes/60)
|
|
10
10
|
*/
|
|
11
|
-
export declare function applyDecay(current: ChemicalState, baseline: ChemicalState, minutesElapsed: number): ChemicalState;
|
|
11
|
+
export declare function applyDecay(current: ChemicalState, baseline: ChemicalState, minutesElapsed: number, decayRateModifiers?: Partial<Record<keyof ChemicalState, number>>): ChemicalState;
|
|
12
12
|
/**
|
|
13
13
|
* Apply a stimulus to the current state.
|
|
14
14
|
* Respects emotional inertia (maxDelta) and personality sensitivity.
|
|
@@ -16,7 +16,7 @@ export declare function applyDecay(current: ChemicalState, baseline: ChemicalSta
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function applyStimulus(current: ChemicalState, stimulus: StimulusType, sensitivity: number, maxDelta: number, logger?: {
|
|
18
18
|
warn: (msg: string) => void;
|
|
19
|
-
}): ChemicalState;
|
|
19
|
+
}, recentSameCount?: number): ChemicalState;
|
|
20
20
|
/**
|
|
21
21
|
* Apply emotional contagion: the detected user emotion partially
|
|
22
22
|
* influences the agent's chemistry.
|
package/dist/chemistry.js
CHANGED
|
@@ -133,13 +133,22 @@ export function clamp(v) {
|
|
|
133
133
|
*
|
|
134
134
|
* decayed = baseline + (current - baseline) * factor^(minutes/60)
|
|
135
135
|
*/
|
|
136
|
-
export function applyDecay(current, baseline, minutesElapsed) {
|
|
136
|
+
export function applyDecay(current, baseline, minutesElapsed, decayRateModifiers) {
|
|
137
137
|
if (minutesElapsed <= 0)
|
|
138
138
|
return { ...current };
|
|
139
139
|
const result = { ...current };
|
|
140
140
|
for (const key of CHEMICAL_KEYS) {
|
|
141
141
|
const speed = CHEMICAL_DECAY_SPEED[key];
|
|
142
|
-
const
|
|
142
|
+
const baseFactor = Math.pow(DECAY_FACTORS[speed], minutesElapsed / 60);
|
|
143
|
+
// v9: decayRateModifiers alter decay speed per chemical
|
|
144
|
+
// > 1 = slower recovery (trauma: factor closer to 1)
|
|
145
|
+
// < 1 = faster recovery (resilience: factor closer to 0)
|
|
146
|
+
let factor = baseFactor;
|
|
147
|
+
if (decayRateModifiers?.[key] !== undefined) {
|
|
148
|
+
const mod = decayRateModifiers[key];
|
|
149
|
+
// Raise the factor to the modifier power: mod>1 → slower decay, mod<1 → faster
|
|
150
|
+
factor = Math.pow(baseFactor, 1 / mod);
|
|
151
|
+
}
|
|
143
152
|
result[key] = clamp(baseline[key] + (current[key] - baseline[key]) * factor);
|
|
144
153
|
}
|
|
145
154
|
return result;
|
|
@@ -149,15 +158,21 @@ export function applyDecay(current, baseline, minutesElapsed) {
|
|
|
149
158
|
* Respects emotional inertia (maxDelta) and personality sensitivity.
|
|
150
159
|
* Logs a warning for unknown stimulus types.
|
|
151
160
|
*/
|
|
152
|
-
export function applyStimulus(current, stimulus, sensitivity, maxDelta, logger) {
|
|
161
|
+
export function applyStimulus(current, stimulus, sensitivity, maxDelta, logger, recentSameCount) {
|
|
153
162
|
const vector = STIMULUS_VECTORS[stimulus];
|
|
154
163
|
if (!vector) {
|
|
155
164
|
logger?.warn(t("log.unknown_stimulus", "zh", { type: stimulus }));
|
|
156
165
|
return { ...current };
|
|
157
166
|
}
|
|
167
|
+
// v9: Habituation — Weber-Fechner diminishing returns
|
|
168
|
+
// First 2 exposures: 100%. 3rd: 77%, 5th: 53%, 10th: 29%
|
|
169
|
+
let effectiveSensitivity = sensitivity;
|
|
170
|
+
if (recentSameCount !== undefined && recentSameCount > 2) {
|
|
171
|
+
effectiveSensitivity *= 1 / (1 + 0.3 * (recentSameCount - 2));
|
|
172
|
+
}
|
|
158
173
|
const result = { ...current };
|
|
159
174
|
for (const key of CHEMICAL_KEYS) {
|
|
160
|
-
const raw = vector[key] *
|
|
175
|
+
const raw = vector[key] * effectiveSensitivity;
|
|
161
176
|
const clamped = Math.max(-maxDelta, Math.min(maxDelta, raw));
|
|
162
177
|
result[key] = clamp(current[key] + clamped);
|
|
163
178
|
}
|
package/dist/circadian.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChemicalState } from "./types.js";
|
|
1
|
+
import type { ChemicalState, EnergyBudgets, StimulusType } from "./types.js";
|
|
2
2
|
export type CircadianPhase = "morning" | "midday" | "afternoon" | "evening" | "night";
|
|
3
3
|
/**
|
|
4
4
|
* Classify a time into a circadian phase.
|
|
@@ -35,3 +35,21 @@ export declare function computeHomeostaticPressure(sessionMinutes: number): {
|
|
|
35
35
|
daDepletion: number;
|
|
36
36
|
neDepletion: number;
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Deplete energy budgets from a single interaction turn.
|
|
40
|
+
*
|
|
41
|
+
* - Attention: -3/turn base, extra for intellectual/conflict
|
|
42
|
+
* - Social energy: extraverts +2/turn (charging), introverts -3/turn (draining)
|
|
43
|
+
* - Decision capacity: varies by stimulus complexity
|
|
44
|
+
*
|
|
45
|
+
* Extraverts can exceed 100 (up to 120 — "supercharged").
|
|
46
|
+
*/
|
|
47
|
+
export declare function computeEnergyDepletion(budgets: EnergyBudgets, stimulus: StimulusType | null, isExtravert: boolean): EnergyBudgets;
|
|
48
|
+
/**
|
|
49
|
+
* Recover energy budgets during absence (between sessions or long pauses).
|
|
50
|
+
*
|
|
51
|
+
* - Attention: +20/hour
|
|
52
|
+
* - Social energy: extraverts -3/hour (drain when alone), introverts +15/hour (recharge)
|
|
53
|
+
* - Decision capacity: +25/hour
|
|
54
|
+
*/
|
|
55
|
+
export declare function computeEnergyRecovery(budgets: EnergyBudgets, minutesElapsed: number, isExtravert: boolean): EnergyBudgets;
|
package/dist/circadian.js
CHANGED
|
@@ -95,3 +95,69 @@ export function computeHomeostaticPressure(sessionMinutes) {
|
|
|
95
95
|
neDepletion: parseFloat((base * 2.5).toFixed(4)),
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
+
// ── Energy Budgets (v9) ─────────────────────────────────────
|
|
99
|
+
// Finite cognitive/social resources that deplete during interaction.
|
|
100
|
+
// Extraverts GAIN social energy from interaction; introverts LOSE it.
|
|
101
|
+
/** Stimulus-specific attention costs (higher = more draining) */
|
|
102
|
+
const ATTENTION_COSTS = {
|
|
103
|
+
intellectual: 5,
|
|
104
|
+
conflict: 5,
|
|
105
|
+
authority: 4,
|
|
106
|
+
vulnerability: 3,
|
|
107
|
+
sarcasm: 3,
|
|
108
|
+
criticism: 3,
|
|
109
|
+
surprise: 2,
|
|
110
|
+
};
|
|
111
|
+
/** Stimulus-specific decision costs */
|
|
112
|
+
const DECISION_COSTS = {
|
|
113
|
+
conflict: 4,
|
|
114
|
+
authority: 4,
|
|
115
|
+
vulnerability: 3,
|
|
116
|
+
criticism: 2,
|
|
117
|
+
sarcasm: 2,
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Deplete energy budgets from a single interaction turn.
|
|
121
|
+
*
|
|
122
|
+
* - Attention: -3/turn base, extra for intellectual/conflict
|
|
123
|
+
* - Social energy: extraverts +2/turn (charging), introverts -3/turn (draining)
|
|
124
|
+
* - Decision capacity: varies by stimulus complexity
|
|
125
|
+
*
|
|
126
|
+
* Extraverts can exceed 100 (up to 120 — "supercharged").
|
|
127
|
+
*/
|
|
128
|
+
export function computeEnergyDepletion(budgets, stimulus, isExtravert) {
|
|
129
|
+
const extravertMax = 120;
|
|
130
|
+
const introvertMax = 100;
|
|
131
|
+
const max = isExtravert ? extravertMax : introvertMax;
|
|
132
|
+
// Attention: base -3, extra from stimulus
|
|
133
|
+
const attentionCost = 3 + (stimulus ? (ATTENTION_COSTS[stimulus] ?? 0) : 0);
|
|
134
|
+
const attention = clamp(budgets.attention - attentionCost, 0, 100);
|
|
135
|
+
// Social energy: E charges, I drains
|
|
136
|
+
const socialDelta = isExtravert ? 2 : -3;
|
|
137
|
+
const socialEnergy = clamp(budgets.socialEnergy + socialDelta, 0, max);
|
|
138
|
+
// Decision capacity: base -1, extra from stimulus
|
|
139
|
+
const decisionCost = 1 + (stimulus ? (DECISION_COSTS[stimulus] ?? 0) : 0);
|
|
140
|
+
const decisionCapacity = clamp(budgets.decisionCapacity - decisionCost, 0, 100);
|
|
141
|
+
return { attention, socialEnergy, decisionCapacity };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Recover energy budgets during absence (between sessions or long pauses).
|
|
145
|
+
*
|
|
146
|
+
* - Attention: +20/hour
|
|
147
|
+
* - Social energy: extraverts -3/hour (drain when alone), introverts +15/hour (recharge)
|
|
148
|
+
* - Decision capacity: +25/hour
|
|
149
|
+
*/
|
|
150
|
+
export function computeEnergyRecovery(budgets, minutesElapsed, isExtravert) {
|
|
151
|
+
if (minutesElapsed <= 0)
|
|
152
|
+
return { ...budgets };
|
|
153
|
+
const hours = minutesElapsed / 60;
|
|
154
|
+
const extravertMax = 120;
|
|
155
|
+
const introvertMax = 100;
|
|
156
|
+
const max = isExtravert ? extravertMax : introvertMax;
|
|
157
|
+
const attention = clamp(budgets.attention + hours * 20, 0, 100);
|
|
158
|
+
// E drains alone, I recharges alone
|
|
159
|
+
const socialDelta = isExtravert ? -3 * hours : 15 * hours;
|
|
160
|
+
const socialEnergy = clamp(budgets.socialEnergy + socialDelta, 0, max);
|
|
161
|
+
const decisionCapacity = clamp(budgets.decisionCapacity + hours * 25, 0, 100);
|
|
162
|
+
return { attention, socialEnergy, decisionCapacity };
|
|
163
|
+
}
|
package/dist/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits } from "./types.js";
|
|
1
|
+
import type { PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits, PolicyModifiers } from "./types.js";
|
|
2
2
|
import type { StorageAdapter } from "./storage.js";
|
|
3
3
|
export interface PsycheEngineConfig {
|
|
4
4
|
mbti?: MBTIType;
|
|
@@ -25,6 +25,8 @@ export interface ProcessInputResult {
|
|
|
25
25
|
dynamicContext: string;
|
|
26
26
|
/** Detected stimulus type from user input, null if none */
|
|
27
27
|
stimulus: StimulusType | null;
|
|
28
|
+
/** v9: Structured behavioral policy modifiers — machine-readable "off baseline" signals */
|
|
29
|
+
policyModifiers?: PolicyModifiers;
|
|
28
30
|
}
|
|
29
31
|
export interface ProcessOutputResult {
|
|
30
32
|
/** LLM output with <psyche_update> tags stripped */
|
package/dist/core.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
//
|
|
12
12
|
// Orchestrates: chemistry, classify, prompt, profiles, guards, learning
|
|
13
13
|
// ============================================================
|
|
14
|
-
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE } from "./types.js";
|
|
14
|
+
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT } from "./types.js";
|
|
15
15
|
import { MemoryStorageAdapter } from "./storage.js";
|
|
16
16
|
import { applyDecay, applyStimulus, applyContagion, clamp, describeEmotionalState } from "./chemistry.js";
|
|
17
17
|
import { classifyStimulus } from "./classify.js";
|
|
@@ -23,12 +23,12 @@ import { decayDrives, feedDrives, detectExistentialThreat, computeEffectiveBasel
|
|
|
23
23
|
import { checkForUpdate } from "./update.js";
|
|
24
24
|
import { evaluateOutcome, computeContextHash, updateLearnedVector, predictChemistry, recordPrediction, } from "./learning.js";
|
|
25
25
|
import { assessMetacognition } from "./metacognition.js";
|
|
26
|
-
import { buildDecisionContext } from "./decision-bias.js";
|
|
26
|
+
import { buildDecisionContext, computePolicyModifiers, buildPolicyContext } from "./decision-bias.js";
|
|
27
27
|
import { computeExperientialField } from "./experiential-field.js";
|
|
28
28
|
import { computeGenerativeSelf } from "./generative-self.js";
|
|
29
29
|
import { updateSharedIntentionality, buildSharedIntentionalityContext } from "./shared-intentionality.js";
|
|
30
30
|
import { assessEthics, buildEthicalContext } from "./ethics.js";
|
|
31
|
-
import { computeCircadianModulation, computeHomeostaticPressure } from "./circadian.js";
|
|
31
|
+
import { computeCircadianModulation, computeHomeostaticPressure, computeEnergyDepletion, computeEnergyRecovery } from "./circadian.js";
|
|
32
32
|
import { computeAutonomicResult } from "./autonomic.js";
|
|
33
33
|
import { computePrimarySystems, computeSystemInteractions, gatePrimarySystemsByAutonomic, describeBehavioralTendencies, } from "./primary-systems.js";
|
|
34
34
|
const NOOP_LOGGER = { info: () => { }, warn: () => { }, debug: () => { } };
|
|
@@ -91,6 +91,16 @@ export class PsycheEngine {
|
|
|
91
91
|
loaded.sessionStartedAt = new Date().toISOString();
|
|
92
92
|
loaded.version = 7;
|
|
93
93
|
}
|
|
94
|
+
// Migrate v7 → v8: P8 Barrett construction + P10 processing depth + P11 memory consolidation
|
|
95
|
+
// No data changes needed — ChemicalSnapshot new fields are optional (backward compatible)
|
|
96
|
+
if (loaded.version < 8) {
|
|
97
|
+
loaded.version = 8;
|
|
98
|
+
}
|
|
99
|
+
// Migrate v8 → v9: PolicyModifiers, TraitDrift, EnergyBudgets, Habituation
|
|
100
|
+
// All new fields are optional — no data migration needed
|
|
101
|
+
if (loaded.version < 9) {
|
|
102
|
+
loaded.version = 9;
|
|
103
|
+
}
|
|
94
104
|
this.state = loaded;
|
|
95
105
|
}
|
|
96
106
|
else {
|
|
@@ -136,13 +146,13 @@ export class PsycheEngine {
|
|
|
136
146
|
// Decay drives first — needs build up over time
|
|
137
147
|
const decayedDrives = decayDrives(state.drives, minutesElapsed);
|
|
138
148
|
// Compute effective baseline from drives (unsatisfied drives shift baseline)
|
|
139
|
-
const effectiveBaseline = computeEffectiveBaseline(state.baseline, decayedDrives);
|
|
149
|
+
const effectiveBaseline = computeEffectiveBaseline(state.baseline, decayedDrives, state.traitDrift);
|
|
140
150
|
// P12: Apply circadian rhythm modulation to effective baseline
|
|
141
151
|
const circadianBaseline = computeCircadianModulation(now, effectiveBaseline);
|
|
142
152
|
state = {
|
|
143
153
|
...state,
|
|
144
154
|
drives: decayedDrives,
|
|
145
|
-
current: applyDecay(state.current, circadianBaseline, minutesElapsed),
|
|
155
|
+
current: applyDecay(state.current, circadianBaseline, minutesElapsed, state.traitDrift?.decayRateModifiers),
|
|
146
156
|
updatedAt: now.toISOString(),
|
|
147
157
|
};
|
|
148
158
|
}
|
|
@@ -164,6 +174,12 @@ export class PsycheEngine {
|
|
|
164
174
|
},
|
|
165
175
|
};
|
|
166
176
|
}
|
|
177
|
+
// v9: Energy budget recovery during absence + depletion per turn
|
|
178
|
+
const isExtravert = this.cfg.mbti.startsWith("E");
|
|
179
|
+
const currentBudgets = state.energyBudgets ?? { ...DEFAULT_ENERGY_BUDGETS };
|
|
180
|
+
let energyBudgets = minutesElapsed >= 5
|
|
181
|
+
? computeEnergyRecovery(currentBudgets, minutesElapsed, isExtravert)
|
|
182
|
+
: { ...currentBudgets };
|
|
167
183
|
// Classify user stimulus and apply chemistry
|
|
168
184
|
let appliedStimulus = null;
|
|
169
185
|
if (text.length > 0) {
|
|
@@ -181,13 +197,19 @@ export class PsycheEngine {
|
|
|
181
197
|
appliedStimulus = primary.type;
|
|
182
198
|
// Feed drives from stimulus, then apply stimulus with drive-modified sensitivity
|
|
183
199
|
drives = feedDrives(drives, primary.type);
|
|
184
|
-
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), drives, primary.type);
|
|
200
|
+
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), drives, primary.type, state.traitDrift);
|
|
185
201
|
const modeMultiplier = this.cfg.mode === "work" ? 0.3 : this.cfg.mode === "companion" ? 1.5 : 1.0;
|
|
186
202
|
const effectiveMaxDelta = this.cfg.mode === "work" ? 5 : this.cfg.maxChemicalDelta;
|
|
187
|
-
|
|
203
|
+
// v9: Habituation — count recent same-type stimuli in this session
|
|
204
|
+
const recentSameCount = (state.emotionalHistory ?? [])
|
|
205
|
+
.filter(s => s.stimulus === primary.type).length + 1; // +1 for current
|
|
206
|
+
current = applyStimulus(current, primary.type, effectiveSensitivity * this.cfg.personalityIntensity * modeMultiplier, effectiveMaxDelta, NOOP_LOGGER, recentSameCount);
|
|
188
207
|
}
|
|
189
208
|
state = { ...state, drives, current };
|
|
190
209
|
}
|
|
210
|
+
// v9: Deplete energy budgets from this interaction turn
|
|
211
|
+
energyBudgets = computeEnergyDepletion(energyBudgets, appliedStimulus, isExtravert);
|
|
212
|
+
state = { ...state, energyBudgets };
|
|
191
213
|
// Conversation warmth: sustained interaction → gentle DA/OT rise, CORT drop
|
|
192
214
|
// Simulates the natural "warm glow" of being in continuous conversation
|
|
193
215
|
const turnsSoFar = (state.emotionalHistory ?? []).length;
|
|
@@ -205,35 +227,40 @@ export class PsycheEngine {
|
|
|
205
227
|
}
|
|
206
228
|
// ── Locale (used by multiple subsystems below) ──────────
|
|
207
229
|
const locale = state.meta.locale ?? this.cfg.locale;
|
|
208
|
-
// ── P7: Autonomic nervous system
|
|
209
|
-
const autonomicResult = computeAutonomicResult(state.current, state.drives, state.autonomicState ?? null, minutesElapsed, locale);
|
|
230
|
+
// ── P7+P10: Autonomic nervous system + Processing depth ────
|
|
231
|
+
const autonomicResult = computeAutonomicResult(state.current, state.drives, state.autonomicState ?? null, minutesElapsed, locale, state.baseline, state.energyBudgets);
|
|
210
232
|
state = {
|
|
211
233
|
...state,
|
|
212
234
|
autonomicState: autonomicResult.state,
|
|
213
235
|
};
|
|
236
|
+
const skip = new Set(autonomicResult.skippedStages);
|
|
214
237
|
// ── P9: Primary emotional systems (Panksepp) ──────────────
|
|
215
238
|
const rawSystems = computePrimarySystems(state.current, state.drives, appliedStimulus);
|
|
216
239
|
const interactedSystems = computeSystemInteractions(rawSystems);
|
|
217
240
|
const gatedSystems = gatePrimarySystemsByAutonomic(interactedSystems, autonomicResult.state);
|
|
218
241
|
const primarySystemsDescription = describeBehavioralTendencies(gatedSystems, locale);
|
|
219
242
|
// ── Metacognition: assess emotional state before acting ────
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
// P10: Skip metacognition when processingDepth < 0.2 (System 1 mode)
|
|
244
|
+
let metacognitiveAssessment = null;
|
|
245
|
+
if (!skip.has("metacognition")) {
|
|
246
|
+
metacognitiveAssessment = assessMetacognition(state, appliedStimulus ?? "casual", state.learning.outcomeHistory);
|
|
247
|
+
// Apply self-soothing regulation if suggested with high confidence
|
|
248
|
+
for (const reg of metacognitiveAssessment.regulationSuggestions) {
|
|
249
|
+
if (reg.strategy === "self-soothing" && reg.confidence >= 0.6 && reg.chemistryAdjustment) {
|
|
250
|
+
const adj = reg.chemistryAdjustment;
|
|
251
|
+
state = {
|
|
252
|
+
...state,
|
|
253
|
+
current: {
|
|
254
|
+
...state.current,
|
|
255
|
+
DA: clamp(state.current.DA + (adj.DA ?? 0)),
|
|
256
|
+
HT: clamp(state.current.HT + (adj.HT ?? 0)),
|
|
257
|
+
CORT: clamp(state.current.CORT + (adj.CORT ?? 0)),
|
|
258
|
+
OT: clamp(state.current.OT + (adj.OT ?? 0)),
|
|
259
|
+
NE: clamp(state.current.NE + (adj.NE ?? 0)),
|
|
260
|
+
END: clamp(state.current.END + (adj.END ?? 0)),
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
237
264
|
}
|
|
238
265
|
}
|
|
239
266
|
// Push snapshot to emotional history
|
|
@@ -248,7 +275,7 @@ export class PsycheEngine {
|
|
|
248
275
|
// ── Generate prediction for next turn's auto-learning ────
|
|
249
276
|
if (appliedStimulus) {
|
|
250
277
|
const ctxHash = computeContextHash(state, opts?.userId);
|
|
251
|
-
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), state.drives, appliedStimulus);
|
|
278
|
+
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), state.drives, appliedStimulus, state.traitDrift);
|
|
252
279
|
const predicted = predictChemistry(preInteractionState.current, appliedStimulus, state.learning, ctxHash, effectiveSensitivity, this.cfg.maxChemicalDelta);
|
|
253
280
|
this.pendingPrediction = {
|
|
254
281
|
predictedChemistry: predicted,
|
|
@@ -260,15 +287,30 @@ export class PsycheEngine {
|
|
|
260
287
|
else {
|
|
261
288
|
this.pendingPrediction = null;
|
|
262
289
|
}
|
|
263
|
-
// ── P6: Digital Personhood computations
|
|
264
|
-
// Experiential field — unified inner experience
|
|
265
|
-
const
|
|
290
|
+
// ── P6: Digital Personhood computations (P10-gated) ────────
|
|
291
|
+
// Experiential field — unified inner experience (P8: Barrett construction context)
|
|
292
|
+
const constructionContext = {
|
|
293
|
+
autonomicState: autonomicResult.state,
|
|
294
|
+
stimulus: appliedStimulus,
|
|
295
|
+
relationshipPhase: (state.relationships._default ?? state.relationships[Object.keys(state.relationships)[0]])?.phase,
|
|
296
|
+
predictionError: state.learning.predictionHistory.length > 0
|
|
297
|
+
? state.learning.predictionHistory[state.learning.predictionHistory.length - 1].predictionError
|
|
298
|
+
: undefined,
|
|
299
|
+
};
|
|
300
|
+
const experientialField = skip.has("experiential-field")
|
|
301
|
+
? null
|
|
302
|
+
: computeExperientialField(state, metacognitiveAssessment ?? undefined, undefined, constructionContext);
|
|
266
303
|
// Shared intentionality — theory of mind + joint attention
|
|
267
|
-
const sharedState =
|
|
304
|
+
const sharedState = skip.has("shared-intentionality")
|
|
305
|
+
? null
|
|
306
|
+
: updateSharedIntentionality(state, appliedStimulus, opts?.userId);
|
|
268
307
|
// Ethics — emotional self-care check
|
|
269
|
-
const ethicalAssessment =
|
|
308
|
+
const ethicalAssessment = skip.has("ethics")
|
|
309
|
+
? null
|
|
310
|
+
: assessEthics(state);
|
|
270
311
|
// Generative self — update identity narrative periodically (every 10 turns)
|
|
271
|
-
if (
|
|
312
|
+
if (!skip.has("generative-self")
|
|
313
|
+
&& state.meta.totalInteractions % 10 === 0 && state.meta.totalInteractions > 0) {
|
|
272
314
|
const selfModel = computeGenerativeSelf(state);
|
|
273
315
|
state = {
|
|
274
316
|
...state,
|
|
@@ -286,7 +328,7 @@ export class PsycheEngine {
|
|
|
286
328
|
};
|
|
287
329
|
}
|
|
288
330
|
// Persist ethical concerns if significant
|
|
289
|
-
if (ethicalAssessment.ethicalHealth < 0.7) {
|
|
331
|
+
if (ethicalAssessment && ethicalAssessment.ethicalHealth < 0.7) {
|
|
290
332
|
const newConcerns = ethicalAssessment.concerns
|
|
291
333
|
.filter((c) => c.severity > 0.4)
|
|
292
334
|
.map((c) => ({ type: c.type, severity: c.severity, timestamp: new Date().toISOString() }));
|
|
@@ -304,7 +346,7 @@ export class PsycheEngine {
|
|
|
304
346
|
}
|
|
305
347
|
}
|
|
306
348
|
// Persist theory of mind
|
|
307
|
-
if (sharedState.theoryOfMind.confidence > 0.3) {
|
|
349
|
+
if (sharedState && sharedState.theoryOfMind.confidence > 0.3) {
|
|
308
350
|
const userId = opts?.userId ?? "_default";
|
|
309
351
|
state = {
|
|
310
352
|
...state,
|
|
@@ -326,11 +368,25 @@ export class PsycheEngine {
|
|
|
326
368
|
this.state = state;
|
|
327
369
|
await this.storage.save(state);
|
|
328
370
|
// Build metacognitive and decision context strings
|
|
329
|
-
const metacogNote = metacognitiveAssessment
|
|
371
|
+
const metacogNote = metacognitiveAssessment?.metacognitiveNote;
|
|
330
372
|
const decisionCtx = buildDecisionContext(state);
|
|
331
|
-
const ethicsCtx = buildEthicalContext(ethicalAssessment, locale);
|
|
332
|
-
const sharedCtx = buildSharedIntentionalityContext(sharedState, locale);
|
|
333
|
-
const experientialNarrative = experientialField
|
|
373
|
+
const ethicsCtx = ethicalAssessment ? buildEthicalContext(ethicalAssessment, locale) : undefined;
|
|
374
|
+
const sharedCtx = sharedState ? buildSharedIntentionalityContext(sharedState, locale) : undefined;
|
|
375
|
+
const experientialNarrative = experientialField?.narrative || undefined;
|
|
376
|
+
// v9: Compute structured policy modifiers
|
|
377
|
+
const policyModifiers = computePolicyModifiers(state);
|
|
378
|
+
const policyCtx = buildPolicyContext(policyModifiers, locale);
|
|
379
|
+
// P10: Append processing depth info to autonomic description when depth is low
|
|
380
|
+
let autonomicDesc;
|
|
381
|
+
if (autonomicResult.state !== "ventral-vagal") {
|
|
382
|
+
autonomicDesc = autonomicResult.description;
|
|
383
|
+
if (autonomicResult.processingDepth < 0.5) {
|
|
384
|
+
const depthNote = locale === "en"
|
|
385
|
+
? " Reflective capacity reduced — intuitive reactions."
|
|
386
|
+
: "反思能力降低——直觉反应中。";
|
|
387
|
+
autonomicDesc += depthNote;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
334
390
|
if (this.cfg.compactMode) {
|
|
335
391
|
return {
|
|
336
392
|
systemContext: "",
|
|
@@ -343,12 +399,12 @@ export class PsycheEngine {
|
|
|
343
399
|
ethicsContext: ethicsCtx || undefined,
|
|
344
400
|
sharedIntentionalityContext: sharedCtx || undefined,
|
|
345
401
|
experientialNarrative: experientialNarrative,
|
|
346
|
-
|
|
347
|
-
autonomicDescription: autonomicResult.state !== "ventral-vagal"
|
|
348
|
-
? autonomicResult.description : undefined,
|
|
402
|
+
autonomicDescription: autonomicDesc,
|
|
349
403
|
primarySystemsDescription: primarySystemsDescription || undefined,
|
|
404
|
+
policyContext: policyCtx || undefined,
|
|
350
405
|
}),
|
|
351
406
|
stimulus: appliedStimulus,
|
|
407
|
+
policyModifiers,
|
|
352
408
|
};
|
|
353
409
|
}
|
|
354
410
|
return {
|
|
@@ -359,11 +415,12 @@ export class PsycheEngine {
|
|
|
359
415
|
ethicsContext: ethicsCtx || undefined,
|
|
360
416
|
sharedIntentionalityContext: sharedCtx || undefined,
|
|
361
417
|
experientialNarrative: experientialNarrative,
|
|
362
|
-
autonomicDescription:
|
|
363
|
-
? autonomicResult.description : undefined,
|
|
418
|
+
autonomicDescription: autonomicDesc,
|
|
364
419
|
primarySystemsDescription: primarySystemsDescription || undefined,
|
|
420
|
+
policyContext: policyCtx || undefined,
|
|
365
421
|
}),
|
|
366
422
|
stimulus: appliedStimulus,
|
|
423
|
+
policyModifiers,
|
|
367
424
|
};
|
|
368
425
|
}
|
|
369
426
|
/**
|
|
@@ -399,7 +456,7 @@ export class PsycheEngine {
|
|
|
399
456
|
...state,
|
|
400
457
|
drives: feedDrives(state.drives, parseResult.llmStimulus),
|
|
401
458
|
};
|
|
402
|
-
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), state.drives, parseResult.llmStimulus);
|
|
459
|
+
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), state.drives, parseResult.llmStimulus, state.traitDrift);
|
|
403
460
|
state = {
|
|
404
461
|
...state,
|
|
405
462
|
current: applyStimulus(state.current, parseResult.llmStimulus, effectiveSensitivity, this.cfg.maxChemicalDelta, NOOP_LOGGER),
|
|
@@ -502,7 +559,7 @@ export class PsycheEngine {
|
|
|
502
559
|
const selfModel = getDefaultSelfModel(mbti);
|
|
503
560
|
const now = new Date().toISOString();
|
|
504
561
|
return {
|
|
505
|
-
version:
|
|
562
|
+
version: 9,
|
|
506
563
|
mbti,
|
|
507
564
|
baseline,
|
|
508
565
|
current: { ...baseline },
|
|
@@ -519,6 +576,8 @@ export class PsycheEngine {
|
|
|
519
576
|
personhood: { ...DEFAULT_PERSONHOOD_STATE },
|
|
520
577
|
autonomicState: "ventral-vagal",
|
|
521
578
|
sessionStartedAt: now,
|
|
579
|
+
traitDrift: { ...DEFAULT_TRAIT_DRIFT },
|
|
580
|
+
energyBudgets: { ...DEFAULT_ENERGY_BUDGETS },
|
|
522
581
|
meta: {
|
|
523
582
|
agentName: name,
|
|
524
583
|
createdAt: now,
|