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/core.js
CHANGED
|
@@ -9,20 +9,21 @@
|
|
|
9
9
|
// Auto-learning: processInput auto-evaluates the previous turn's
|
|
10
10
|
// outcome using the new user message as the outcome signal.
|
|
11
11
|
//
|
|
12
|
-
// Orchestrates:
|
|
12
|
+
// Orchestrates: self-state, classify, prompt, profiles, guards, learning
|
|
13
13
|
// ============================================================
|
|
14
|
-
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD
|
|
14
|
+
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD } 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, BuiltInClassifier, buildLLMClassifierPrompt, parseLLMClassification } from "./classify.js";
|
|
18
|
+
import { perceive } from "./perceive.js";
|
|
18
19
|
import { buildCompactContext, buildProtocolContext } from "./prompt.js";
|
|
19
20
|
import { getSensitivity, getBaseline, getDefaultSelfModel, traitsToBaseline } from "./profiles.js";
|
|
20
21
|
import { isStimulusType } from "./guards.js";
|
|
21
22
|
import { parsePsycheUpdate, mergeUpdates, updateAgreementStreak, pushSnapshot, compressSession, summarizeTurnSemantic, } from "./psyche-file.js";
|
|
22
|
-
import {
|
|
23
|
+
import { detectExistentialThreat, deriveDriveSatisfaction, computeEffectiveBaseline, computeEffectiveSensitivity, } from "./drives.js";
|
|
23
24
|
import { checkForUpdate, getPackageVersion } from "./update.js";
|
|
24
25
|
import { DiagnosticCollector, generateReport, formatLogEntry, submitFeedback } from "./diagnostics.js";
|
|
25
|
-
import { evaluateOutcome, computeContextHash, updateLearnedVector,
|
|
26
|
+
import { evaluateOutcome, computeContextHash, updateLearnedVector, predictState, recordPrediction, } from "./learning.js";
|
|
26
27
|
import { computeCircadianModulation, computeHomeostaticPressure, computeEnergyDepletion, computeEnergyRecovery } from "./circadian.js";
|
|
27
28
|
import { runReflectiveTurnPhases } from "./input-turn.js";
|
|
28
29
|
import { applyRelationalTurn, applySessionBridge, applyWritebackSignals, createWritebackCalibrations, evaluateWritebackCalibrations } from "./relation-dynamics.js";
|
|
@@ -60,22 +61,25 @@ const RELATIONSHIP_DELTAS = {
|
|
|
60
61
|
function applyRepairLag(previous, next, baseline, stimulus) {
|
|
61
62
|
if (!REPAIRING_STIMULI.has(stimulus))
|
|
62
63
|
return next;
|
|
63
|
-
|
|
64
|
+
// Low order = high stress (inverse of old CORT). Stress = baseline.order - previous.order.
|
|
65
|
+
const stressLoad = Math.max(0, baseline.order - previous.order);
|
|
64
66
|
if (stressLoad < 15)
|
|
65
67
|
return next;
|
|
66
68
|
// High stress slows emotional recovery so apology/praise doesn't instantly
|
|
67
|
-
// snap
|
|
69
|
+
// snap state back to baseline.
|
|
68
70
|
const repairFactor = Math.max(0.35, 1 - stressLoad / 50);
|
|
69
71
|
const adjusted = { ...next };
|
|
70
|
-
|
|
72
|
+
// For flow, resonance, boundary: positive deltas (recovery) are damped
|
|
73
|
+
for (const key of ["flow", "resonance", "boundary"]) {
|
|
71
74
|
const delta = next[key] - previous[key];
|
|
72
75
|
if (delta > 0) {
|
|
73
76
|
adjusted[key] = clamp(previous[key] + delta * repairFactor);
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
// For order: recovery means order increasing (stress reducing)
|
|
80
|
+
const orderDelta = next.order - previous.order;
|
|
81
|
+
if (orderDelta > 0) {
|
|
82
|
+
adjusted.order = clamp(previous.order + orderDelta * repairFactor);
|
|
79
83
|
}
|
|
80
84
|
return adjusted;
|
|
81
85
|
}
|
|
@@ -144,7 +148,7 @@ export class PsycheEngine {
|
|
|
144
148
|
locale: config.locale ?? "zh",
|
|
145
149
|
stripUpdateTags: config.stripUpdateTags ?? true,
|
|
146
150
|
emotionalContagionRate: config.emotionalContagionRate ?? 0.2,
|
|
147
|
-
|
|
151
|
+
maxDimensionDelta: config.maxDimensionDelta ?? 25,
|
|
148
152
|
compactMode: config.compactMode ?? true,
|
|
149
153
|
mode: config.mode ?? "natural",
|
|
150
154
|
personalityIntensity: config.personalityIntensity ?? 0.7,
|
|
@@ -189,7 +193,7 @@ export class PsycheEngine {
|
|
|
189
193
|
loaded.version = 7;
|
|
190
194
|
}
|
|
191
195
|
// Migrate v7 → v8: P8 Barrett construction + P10 processing depth + P11 memory consolidation
|
|
192
|
-
// No data changes needed —
|
|
196
|
+
// No data changes needed — StateSnapshot new fields are optional (backward compatible)
|
|
193
197
|
if (loaded.version < 8) {
|
|
194
198
|
loaded.version = 8;
|
|
195
199
|
}
|
|
@@ -245,7 +249,7 @@ export class PsycheEngine {
|
|
|
245
249
|
// Record prediction accuracy
|
|
246
250
|
state = {
|
|
247
251
|
...state,
|
|
248
|
-
learning: recordPrediction(state.learning, this.pendingPrediction.
|
|
252
|
+
learning: recordPrediction(state.learning, this.pendingPrediction.predictedState, state.current, this.pendingPrediction.appliedStimulus),
|
|
249
253
|
};
|
|
250
254
|
// Update learned vectors based on outcome
|
|
251
255
|
if (this.pendingPrediction.appliedStimulus) {
|
|
@@ -262,15 +266,15 @@ export class PsycheEngine {
|
|
|
262
266
|
const now = new Date();
|
|
263
267
|
const minutesElapsed = (now.getTime() - new Date(state.updatedAt).getTime()) / 60000;
|
|
264
268
|
if (minutesElapsed >= 1) {
|
|
265
|
-
//
|
|
266
|
-
const
|
|
267
|
-
// Compute effective baseline from drives (unsatisfied drives shift baseline)
|
|
268
|
-
const effectiveBaseline = computeEffectiveBaseline(state.baseline, decayedDrives, state.traitDrift);
|
|
269
|
+
// Compute effective baseline from current 4D position (drives are derived, not stored)
|
|
270
|
+
const effectiveBaseline = computeEffectiveBaseline(state.baseline, state.current, state.traitDrift);
|
|
269
271
|
// P12: Apply circadian rhythm modulation to effective baseline
|
|
270
272
|
const circadianBaseline = computeCircadianModulation(now, effectiveBaseline);
|
|
273
|
+
// Derive drives from current position for state persistence
|
|
274
|
+
const drives = deriveDriveSatisfaction(state.current, state.baseline);
|
|
271
275
|
state = {
|
|
272
276
|
...state,
|
|
273
|
-
drives
|
|
277
|
+
drives,
|
|
274
278
|
current: applyDecay(state.current, circadianBaseline, minutesElapsed, state.traitDrift?.decayRateModifiers),
|
|
275
279
|
updatedAt: now.toISOString(),
|
|
276
280
|
};
|
|
@@ -285,36 +289,38 @@ export class PsycheEngine {
|
|
|
285
289
|
// Apply homeostatic pressure (fatigue from extended sessions)
|
|
286
290
|
const sessionMinutes = (now.getTime() - new Date(state.sessionStartedAt).getTime()) / 60000;
|
|
287
291
|
const pressure = computeHomeostaticPressure(sessionMinutes);
|
|
288
|
-
if (pressure.
|
|
292
|
+
if (pressure.orderDepletion > 0 || pressure.flowDepletion > 0 || pressure.boundaryStiffening > 0) {
|
|
289
293
|
state = {
|
|
290
294
|
...state,
|
|
291
295
|
current: {
|
|
292
296
|
...state.current,
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
297
|
+
order: clamp(state.current.order - pressure.orderDepletion * 0.1),
|
|
298
|
+
flow: clamp(state.current.flow - pressure.flowDepletion * 0.1),
|
|
299
|
+
boundary: clamp(state.current.boundary + pressure.boundaryStiffening * 0.1),
|
|
296
300
|
},
|
|
297
301
|
};
|
|
298
302
|
}
|
|
299
303
|
// v9: Energy budget recovery during absence + depletion per turn
|
|
300
|
-
const isExtravert = state.baseline.
|
|
304
|
+
const isExtravert = state.baseline.flow >= 55;
|
|
301
305
|
const currentBudgets = state.energyBudgets ?? { ...DEFAULT_ENERGY_BUDGETS };
|
|
302
306
|
let energyBudgets = minutesElapsed >= 5
|
|
303
307
|
? computeEnergyRecovery(currentBudgets, minutesElapsed, isExtravert)
|
|
304
308
|
: { ...currentBudgets };
|
|
305
|
-
//
|
|
309
|
+
// ── Perceive ─────────────────────────────────────────────
|
|
310
|
+
// One act. Text enters the self, chemistry changes, appraisal
|
|
311
|
+
// forms. There is no "classify then feel" — perception is atomic.
|
|
306
312
|
let appliedStimulus = null;
|
|
313
|
+
let perceptionAppraisal;
|
|
307
314
|
if (text.length > 0) {
|
|
308
|
-
//
|
|
315
|
+
// Existential threats → direct survival drive hit (pre-perception)
|
|
309
316
|
const survivalHit = detectExistentialThreat(text);
|
|
310
317
|
let drives = state.drives;
|
|
311
318
|
if (survivalHit < 0) {
|
|
312
319
|
drives = { ...drives, survival: Math.max(0, drives.survival + survivalHit) };
|
|
313
320
|
}
|
|
314
|
-
const recentStimuli = (state.
|
|
315
|
-
//
|
|
321
|
+
const recentStimuli = (state.stateHistory ?? []).slice(-3).map(s => s.stimulus);
|
|
322
|
+
// Pluggable classifier + LLM fallback (raw signal for perception)
|
|
316
323
|
let classifications = await Promise.resolve(this.classifier.classify(text, { recentStimuli, locale: this.cfg.locale }));
|
|
317
|
-
// v9.1: LLM fallback when confidence is low
|
|
318
324
|
if (this.llmClassifier &&
|
|
319
325
|
(!classifications[0] || classifications[0].confidence < this.cfg.llmClassifierThreshold)) {
|
|
320
326
|
try {
|
|
@@ -325,40 +331,45 @@ export class PsycheEngine {
|
|
|
325
331
|
classifications = [llmResult, ...classifications];
|
|
326
332
|
}
|
|
327
333
|
}
|
|
328
|
-
catch {
|
|
329
|
-
// LLM call failed — continue with built-in result
|
|
330
|
-
}
|
|
334
|
+
catch { /* continue with built-in */ }
|
|
331
335
|
}
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
336
|
+
// Resolve relationship trust
|
|
337
|
+
const userId = opts?.userId ?? "__default__";
|
|
338
|
+
const trust = state.relationships?.[userId]?.trust;
|
|
339
|
+
// Perceive: text + self → chemistry + appraisal + annotation
|
|
340
|
+
const perception = perceive(text, {
|
|
341
|
+
current: state.current,
|
|
342
|
+
baseline: state.baseline,
|
|
343
|
+
sensitivity: state.sensitivity ?? 1.0,
|
|
344
|
+
personalityIntensity: this.cfg.personalityIntensity,
|
|
345
|
+
mode: this.cfg.mode,
|
|
346
|
+
maxDimensionDelta: this.cfg.maxDimensionDelta,
|
|
347
|
+
drives,
|
|
348
|
+
previousAppraisal: state.subjectResidue?.axes,
|
|
349
|
+
trust,
|
|
350
|
+
recentStimuli,
|
|
351
|
+
traitDrift: state.traitDrift,
|
|
352
|
+
stateHistory: state.stateHistory,
|
|
353
|
+
locale: this.cfg.locale,
|
|
354
|
+
rawClassifications: classifications,
|
|
355
|
+
});
|
|
356
|
+
appliedStimulus = perception.dominantStimulus;
|
|
357
|
+
perceptionAppraisal = perception.appraisal;
|
|
358
|
+
// Chemistry is already changed inside perceive(). Apply repair lag.
|
|
359
|
+
let current = perception.state;
|
|
360
|
+
if (appliedStimulus) {
|
|
361
|
+
current = applyRepairLag(state.current, current, state.baseline, appliedStimulus);
|
|
353
362
|
}
|
|
363
|
+
// Derive drives from updated position
|
|
364
|
+
drives = deriveDriveSatisfaction(current, state.baseline);
|
|
354
365
|
state = { ...state, drives, current };
|
|
355
366
|
if (appliedStimulus) {
|
|
356
367
|
state = applyRelationshipDrift(state, appliedStimulus, opts?.userId);
|
|
357
368
|
}
|
|
358
369
|
this.lastStimulusAssessment = {
|
|
359
|
-
stimulus:
|
|
360
|
-
confidence:
|
|
361
|
-
overrideWindow:
|
|
370
|
+
stimulus: appliedStimulus,
|
|
371
|
+
confidence: perception.confidence,
|
|
372
|
+
overrideWindow: perception.confidence >= 0.78 ? "narrow" : perception.confidence >= 0.62 ? "balanced" : "wide",
|
|
362
373
|
};
|
|
363
374
|
}
|
|
364
375
|
else {
|
|
@@ -368,29 +379,31 @@ export class PsycheEngine {
|
|
|
368
379
|
overrideWindow: "wide",
|
|
369
380
|
};
|
|
370
381
|
}
|
|
371
|
-
//
|
|
382
|
+
// Deplete energy budgets
|
|
372
383
|
energyBudgets = computeEnergyDepletion(energyBudgets, appliedStimulus, isExtravert);
|
|
373
384
|
state = { ...state, energyBudgets };
|
|
385
|
+
// Relational turn uses pre-computed appraisal from perception
|
|
374
386
|
const relationalTurn = applyRelationalTurn(state, text, {
|
|
375
387
|
mode: this.cfg.mode,
|
|
376
388
|
now: now.toISOString(),
|
|
377
389
|
stimulus: appliedStimulus,
|
|
378
390
|
userId: opts?.userId,
|
|
391
|
+
preComputedAppraisal: perceptionAppraisal,
|
|
379
392
|
});
|
|
380
393
|
state = relationalTurn.state;
|
|
381
394
|
const appraisalAxes = relationalTurn.appraisalAxes;
|
|
382
|
-
// Conversation warmth: sustained interaction → gentle
|
|
395
|
+
// Conversation warmth: sustained interaction → gentle flow/resonance rise, order stabilization
|
|
383
396
|
// Simulates the natural "warm glow" of being in continuous conversation
|
|
384
|
-
const turnsSoFar = (state.
|
|
397
|
+
const turnsSoFar = (state.stateHistory ?? []).length;
|
|
385
398
|
if (minutesElapsed < 5 && turnsSoFar > 0) {
|
|
386
399
|
const warmth = Math.min(3, 1 + turnsSoFar * 0.2);
|
|
387
400
|
state = {
|
|
388
401
|
...state,
|
|
389
402
|
current: {
|
|
390
403
|
...state.current,
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
404
|
+
flow: clamp(state.current.flow + warmth),
|
|
405
|
+
resonance: clamp(state.current.resonance + warmth),
|
|
406
|
+
order: clamp(state.current.order + 1),
|
|
394
407
|
},
|
|
395
408
|
};
|
|
396
409
|
}
|
|
@@ -424,10 +437,10 @@ export class PsycheEngine {
|
|
|
424
437
|
// ── Generate prediction for next turn's auto-learning ────
|
|
425
438
|
if (appliedStimulus) {
|
|
426
439
|
const ctxHash = computeContextHash(state, opts?.userId);
|
|
427
|
-
const effectiveSensitivity = computeEffectiveSensitivity((state.sensitivity ?? 1.0), state.
|
|
428
|
-
const predicted =
|
|
440
|
+
const effectiveSensitivity = computeEffectiveSensitivity((state.sensitivity ?? 1.0), state.current, state.baseline, appliedStimulus, state.traitDrift);
|
|
441
|
+
const predicted = predictState(preInteractionState.current, appliedStimulus, state.learning, ctxHash, effectiveSensitivity, this.cfg.maxDimensionDelta);
|
|
429
442
|
this.pendingPrediction = {
|
|
430
|
-
|
|
443
|
+
predictedState: predicted,
|
|
431
444
|
preInteractionState,
|
|
432
445
|
appliedStimulus,
|
|
433
446
|
contextHash: ctxHash,
|
|
@@ -552,16 +565,16 @@ export class PsycheEngine {
|
|
|
552
565
|
const RELEASE_TYPES = new Set([
|
|
553
566
|
"vulnerability", "intimacy", "validation",
|
|
554
567
|
]);
|
|
555
|
-
if (RELEASE_TYPES.has(selfPrimary.type) && state.current.
|
|
556
|
-
const stressExcess = (state.current.
|
|
557
|
-
const recoveryMagnitude = 3 + stressExcess * 5; // 3–8 point
|
|
568
|
+
if (RELEASE_TYPES.has(selfPrimary.type) && state.current.order < 40) {
|
|
569
|
+
const stressExcess = (40 - state.current.order) / 40; // 0 at order=40, 1 at order=0
|
|
570
|
+
const recoveryMagnitude = 3 + stressExcess * 5; // 3–8 point recovery
|
|
558
571
|
state = {
|
|
559
572
|
...state,
|
|
560
573
|
current: {
|
|
561
574
|
...state.current,
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
575
|
+
order: clamp(state.current.order + recoveryMagnitude),
|
|
576
|
+
resonance: clamp(state.current.resonance + recoveryMagnitude * 0.6),
|
|
577
|
+
boundary: clamp(state.current.boundary + recoveryMagnitude * 0.3),
|
|
565
578
|
},
|
|
566
579
|
};
|
|
567
580
|
}
|
|
@@ -575,20 +588,18 @@ export class PsycheEngine {
|
|
|
575
588
|
if (text.includes("<psyche_update>")) {
|
|
576
589
|
const parseResult = parsePsycheUpdate(text, NOOP_LOGGER);
|
|
577
590
|
if (parseResult) {
|
|
578
|
-
state = mergeUpdates(state, parseResult.state, this.cfg.
|
|
591
|
+
state = mergeUpdates(state, parseResult.state, this.cfg.maxDimensionDelta, opts?.userId);
|
|
579
592
|
stateChanged = true;
|
|
580
593
|
// LLM-assisted classification: if algorithm didn't apply a stimulus
|
|
581
594
|
// but LLM classified one, retroactively apply chemistry + drives
|
|
582
595
|
const overrideAllowed = this.lastStimulusAssessment?.overrideWindow !== "narrow";
|
|
583
596
|
if (parseResult.llmStimulus && (!this._lastAlgorithmApplied || overrideAllowed)) {
|
|
597
|
+
const effectiveSensitivity = computeEffectiveSensitivity((state.sensitivity ?? 1.0), state.current, state.baseline, parseResult.llmStimulus, state.traitDrift);
|
|
598
|
+
const newCurrent = applyStimulus(state.current, parseResult.llmStimulus, effectiveSensitivity * (overrideAllowed && this._lastAlgorithmApplied ? 0.8 : 1), this.cfg.maxDimensionDelta, NOOP_LOGGER);
|
|
584
599
|
state = {
|
|
585
600
|
...state,
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const effectiveSensitivity = computeEffectiveSensitivity((state.sensitivity ?? 1.0), state.drives, parseResult.llmStimulus, state.traitDrift);
|
|
589
|
-
state = {
|
|
590
|
-
...state,
|
|
591
|
-
current: applyStimulus(state.current, parseResult.llmStimulus, effectiveSensitivity * (overrideAllowed && this._lastAlgorithmApplied ? 0.8 : 1), this.cfg.maxChemicalDelta, NOOP_LOGGER),
|
|
601
|
+
current: newCurrent,
|
|
602
|
+
drives: deriveDriveSatisfaction(newCurrent, state.baseline),
|
|
592
603
|
};
|
|
593
604
|
}
|
|
594
605
|
if (parseResult.signals && parseResult.signals.length > 0) {
|
|
@@ -653,7 +664,7 @@ export class PsycheEngine {
|
|
|
653
664
|
// Record prediction
|
|
654
665
|
state = {
|
|
655
666
|
...state,
|
|
656
|
-
learning: recordPrediction(state.learning, pending.
|
|
667
|
+
learning: recordPrediction(state.learning, pending.predictedState, state.current, pending.appliedStimulus),
|
|
657
668
|
};
|
|
658
669
|
// Update learned vectors
|
|
659
670
|
let learningUpdated = false;
|
|
@@ -687,7 +698,7 @@ export class PsycheEngine {
|
|
|
687
698
|
return cached;
|
|
688
699
|
}
|
|
689
700
|
/**
|
|
690
|
-
* End the current session: compress
|
|
701
|
+
* End the current session: compress stateHistory into a rich summary
|
|
691
702
|
* stored in relationship.memory[], then preserve only core/recent context.
|
|
692
703
|
* Auto-generates diagnostic report and persists to log.
|
|
693
704
|
*
|
|
@@ -715,7 +726,7 @@ export class PsycheEngine {
|
|
|
715
726
|
submitFeedback(report, this.feedbackUrl).catch(() => { });
|
|
716
727
|
}
|
|
717
728
|
}
|
|
718
|
-
if ((state.
|
|
729
|
+
if ((state.stateHistory ?? []).length >= 2) {
|
|
719
730
|
state = compressSession(state, opts?.userId);
|
|
720
731
|
}
|
|
721
732
|
// Reset session tracking for homeostatic pressure
|
|
@@ -784,7 +795,7 @@ export class PsycheEngine {
|
|
|
784
795
|
relationships: { _default: { ...DEFAULT_RELATIONSHIP } },
|
|
785
796
|
empathyLog: null,
|
|
786
797
|
selfModel,
|
|
787
|
-
|
|
798
|
+
stateHistory: [],
|
|
788
799
|
agreementStreak: 0,
|
|
789
800
|
lastDisagreement: null,
|
|
790
801
|
learning: { ...DEFAULT_LEARNING_STATE },
|
|
@@ -828,7 +839,7 @@ export class PsycheEngine {
|
|
|
828
839
|
current: { ...baseline },
|
|
829
840
|
baseline,
|
|
830
841
|
drives: { ...DEFAULT_DRIVES },
|
|
831
|
-
|
|
842
|
+
stateHistory: [],
|
|
832
843
|
agreementStreak: 0,
|
|
833
844
|
lastDisagreement: null,
|
|
834
845
|
empathyLog: null,
|
|
@@ -863,16 +874,16 @@ export class PsycheEngine {
|
|
|
863
874
|
const state = this.ensureInitialized();
|
|
864
875
|
const locale = state.meta.locale ?? "zh";
|
|
865
876
|
const emotion = describeEmotionalState(state.current, locale);
|
|
866
|
-
const {
|
|
877
|
+
const { flow, order } = state.current;
|
|
867
878
|
// Emoji based on dominant state
|
|
868
879
|
let emoji = "\u{1F610}";
|
|
869
|
-
if (
|
|
880
|
+
if (flow > 70 && order > 60)
|
|
870
881
|
emoji = "\u{1F60A}";
|
|
871
|
-
else if (
|
|
882
|
+
else if (flow > 60)
|
|
872
883
|
emoji = "\u{1F642}";
|
|
873
|
-
else if (
|
|
884
|
+
else if (order < 40)
|
|
874
885
|
emoji = "\u{1F630}";
|
|
875
|
-
else if (
|
|
886
|
+
else if (flow < 35)
|
|
876
887
|
emoji = "\u{1F614}";
|
|
877
888
|
// Check for hungry drives
|
|
878
889
|
const hungryDrives = Object.entries(state.drives)
|
|
@@ -881,6 +892,6 @@ export class PsycheEngine {
|
|
|
881
892
|
const driveWarning = hungryDrives.length > 0
|
|
882
893
|
? ` | \u26A0\uFE0F${hungryDrives.join(",")}`
|
|
883
894
|
: "";
|
|
884
|
-
return `${emoji} ${emotion} |
|
|
895
|
+
return `${emoji} ${emotion} | flow:${Math.round(flow)} order:${Math.round(order)}${driveWarning}`;
|
|
885
896
|
}
|
|
886
897
|
}
|
package/dist/custom-profile.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SelfState, MBTIType, StimulusType, SelfModel, InnateDrives } from "./types.js";
|
|
2
2
|
/** Configuration for creating a custom personality profile */
|
|
3
3
|
export interface CustomProfileConfig {
|
|
4
4
|
/** Unique name for the profile, e.g. "cheerful-assistant", "stoic-mentor" */
|
|
5
5
|
name: string;
|
|
6
6
|
/** Optional description of the personality */
|
|
7
7
|
description?: string;
|
|
8
|
-
/** Override specific
|
|
9
|
-
baseline?: Partial<
|
|
8
|
+
/** Override specific dimensions; rest inherited from baseMBTI */
|
|
9
|
+
baseline?: Partial<SelfState>;
|
|
10
10
|
/** Which MBTI to use as starting point (default: "INFJ") */
|
|
11
11
|
baseMBTI?: MBTIType;
|
|
12
12
|
/** Override specific stimulus sensitivities (0.1-3.0) */
|
|
@@ -30,7 +30,7 @@ export interface ResolvedProfile {
|
|
|
30
30
|
name: string;
|
|
31
31
|
description: string;
|
|
32
32
|
baseMBTI: MBTIType;
|
|
33
|
-
baseline:
|
|
33
|
+
baseline: SelfState;
|
|
34
34
|
sensitivityMap: Record<StimulusType, number>;
|
|
35
35
|
temperament: {
|
|
36
36
|
expressiveness: number;
|
|
@@ -61,10 +61,10 @@ export declare const PRESET_PROFILES: {
|
|
|
61
61
|
description: string;
|
|
62
62
|
baseMBTI: MBTIType;
|
|
63
63
|
baseline: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
order: number;
|
|
65
|
+
flow: number;
|
|
66
|
+
boundary: number;
|
|
67
|
+
resonance: number;
|
|
68
68
|
};
|
|
69
69
|
temperament: {
|
|
70
70
|
expressiveness: number;
|
|
@@ -87,10 +87,10 @@ export declare const PRESET_PROFILES: {
|
|
|
87
87
|
description: string;
|
|
88
88
|
baseMBTI: MBTIType;
|
|
89
89
|
baseline: {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
order: number;
|
|
91
|
+
flow: number;
|
|
92
|
+
boundary: number;
|
|
93
|
+
resonance: number;
|
|
94
94
|
};
|
|
95
95
|
sensitivity: Partial<Record<StimulusType, number>>;
|
|
96
96
|
temperament: {
|
|
@@ -110,10 +110,10 @@ export declare const PRESET_PROFILES: {
|
|
|
110
110
|
description: string;
|
|
111
111
|
baseMBTI: MBTIType;
|
|
112
112
|
baseline: {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
order: number;
|
|
114
|
+
flow: number;
|
|
115
|
+
boundary: number;
|
|
116
|
+
resonance: number;
|
|
117
117
|
};
|
|
118
118
|
sensitivity: Partial<Record<StimulusType, number>>;
|
|
119
119
|
temperament: {
|
|
@@ -136,10 +136,10 @@ export declare const PRESET_PROFILES: {
|
|
|
136
136
|
description: string;
|
|
137
137
|
baseMBTI: MBTIType;
|
|
138
138
|
baseline: {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
order: number;
|
|
140
|
+
flow: number;
|
|
141
|
+
boundary: number;
|
|
142
|
+
resonance: number;
|
|
143
143
|
};
|
|
144
144
|
sensitivity: Partial<Record<StimulusType, number>>;
|
|
145
145
|
temperament: {
|
package/dist/custom-profile.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Allows creating fully customized personality profiles that
|
|
5
5
|
// start from an MBTI base and override specific parameters.
|
|
6
6
|
// ============================================================
|
|
7
|
-
import {
|
|
7
|
+
import { DIMENSION_KEYS, DEFAULT_DRIVES, DRIVE_KEYS } from "./types.js";
|
|
8
8
|
import { getBaseline, getDefaultSelfModel, getSensitivity } from "./profiles.js";
|
|
9
9
|
import { isMBTIType, isStimulusType } from "./guards.js";
|
|
10
10
|
// ── Stimulus type list for iteration ────────────────────────
|
|
@@ -14,7 +14,7 @@ const ALL_STIMULUS_TYPES = [
|
|
|
14
14
|
"sarcasm", "authority", "validation", "boredom", "vulnerability",
|
|
15
15
|
];
|
|
16
16
|
// ── Clamping helpers ────────────────────────────────────────
|
|
17
|
-
function
|
|
17
|
+
function clampDimension(v) {
|
|
18
18
|
return Math.max(0, Math.min(100, v));
|
|
19
19
|
}
|
|
20
20
|
function clampSensitivity(v) {
|
|
@@ -48,12 +48,12 @@ export function createCustomProfile(config) {
|
|
|
48
48
|
const baseSensitivity = getSensitivity(baseMBTI);
|
|
49
49
|
const baseSelfModel = getDefaultSelfModel(baseMBTI);
|
|
50
50
|
const baseTemperament = defaultTemperamentFromMBTI(baseMBTI);
|
|
51
|
-
// Merge baseline: start from MBTI, override specific
|
|
51
|
+
// Merge baseline: start from MBTI, override specific dimensions
|
|
52
52
|
const baseline = { ...baseBaseline };
|
|
53
53
|
if (config.baseline) {
|
|
54
|
-
for (const key of
|
|
54
|
+
for (const key of DIMENSION_KEYS) {
|
|
55
55
|
if (config.baseline[key] !== undefined) {
|
|
56
|
-
baseline[key] =
|
|
56
|
+
baseline[key] = clampDimension(config.baseline[key]);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -127,7 +127,7 @@ export function validateProfileConfig(config) {
|
|
|
127
127
|
errors.push("baseMBTI must be a valid MBTI type (e.g. INFJ, ENTP)");
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
-
// baseline: optional partial
|
|
130
|
+
// baseline: optional partial SelfState
|
|
131
131
|
if (obj.baseline !== undefined) {
|
|
132
132
|
if (typeof obj.baseline !== "object" || obj.baseline === null || Array.isArray(obj.baseline)) {
|
|
133
133
|
errors.push("baseline must be an object");
|
|
@@ -135,8 +135,8 @@ export function validateProfileConfig(config) {
|
|
|
135
135
|
else {
|
|
136
136
|
const bl = obj.baseline;
|
|
137
137
|
for (const key of Object.keys(bl)) {
|
|
138
|
-
if (!
|
|
139
|
-
errors.push(`baseline.${key} is not a valid
|
|
138
|
+
if (!DIMENSION_KEYS.includes(key)) {
|
|
139
|
+
errors.push(`baseline.${key} is not a valid dimension key (valid: ${DIMENSION_KEYS.join(", ")})`);
|
|
140
140
|
}
|
|
141
141
|
else if (typeof bl[key] !== "number" || !isFinite(bl[key])) {
|
|
142
142
|
errors.push(`baseline.${key} must be a finite number`);
|
|
@@ -240,7 +240,7 @@ export const PRESET_PROFILES = {
|
|
|
240
240
|
name: "cheerful",
|
|
241
241
|
description: "Sunny, warm personality with high energy and emotional stability",
|
|
242
242
|
baseMBTI: "ENFP",
|
|
243
|
-
baseline: {
|
|
243
|
+
baseline: { order: 65, flow: 80, boundary: 50, resonance: 75 },
|
|
244
244
|
temperament: {
|
|
245
245
|
expressiveness: 0.9,
|
|
246
246
|
volatility: 0.2,
|
|
@@ -258,7 +258,7 @@ export const PRESET_PROFILES = {
|
|
|
258
258
|
name: "stoic",
|
|
259
259
|
description: "Calm, measured personality with emotional restraint and deep resilience",
|
|
260
260
|
baseMBTI: "INTJ",
|
|
261
|
-
baseline: {
|
|
261
|
+
baseline: { order: 75, flow: 45, boundary: 72, resonance: 35 },
|
|
262
262
|
sensitivity: {
|
|
263
263
|
praise: 0.3,
|
|
264
264
|
criticism: 0.4,
|
|
@@ -285,7 +285,7 @@ export const PRESET_PROFILES = {
|
|
|
285
285
|
name: "empathetic",
|
|
286
286
|
description: "Deeply attuned to others' emotions, strong bonding instinct",
|
|
287
287
|
baseMBTI: "INFJ",
|
|
288
|
-
baseline: {
|
|
288
|
+
baseline: { order: 60, flow: 55, boundary: 45, resonance: 80 },
|
|
289
289
|
sensitivity: {
|
|
290
290
|
intimacy: 2.5,
|
|
291
291
|
vulnerability: 2.8,
|
|
@@ -310,7 +310,7 @@ export const PRESET_PROFILES = {
|
|
|
310
310
|
name: "analytical",
|
|
311
311
|
description: "Sharp, focused personality driven by intellectual curiosity",
|
|
312
312
|
baseMBTI: "INTP",
|
|
313
|
-
baseline: {
|
|
313
|
+
baseline: { order: 60, flow: 75, boundary: 68, resonance: 30 },
|
|
314
314
|
sensitivity: {
|
|
315
315
|
intellectual: 2.5,
|
|
316
316
|
surprise: 2.0,
|
package/dist/decision-bias.d.ts
CHANGED
|
@@ -17,13 +17,13 @@ export interface AttentionWeights {
|
|
|
17
17
|
/**
|
|
18
18
|
* Compute a decision bias vector from the current psyche state.
|
|
19
19
|
*
|
|
20
|
-
* Each bias dimension is a weighted combination of relevant
|
|
21
|
-
*
|
|
20
|
+
* Each bias dimension is a weighted combination of relevant self-state
|
|
21
|
+
* dimensions and drive states, normalized to [0, 1] where 0.5 is neutral.
|
|
22
22
|
*/
|
|
23
23
|
export declare function computeDecisionBias(state: PsycheState): DecisionBiasVector;
|
|
24
24
|
/**
|
|
25
25
|
* Compute attention weights that prioritize different conversation content
|
|
26
|
-
* based on current
|
|
26
|
+
* based on current self-state dimensions.
|
|
27
27
|
*
|
|
28
28
|
* Returns normalized weights (sum to ~1) for each content category.
|
|
29
29
|
* Higher weight = higher priority for that type of content.
|
|
@@ -38,15 +38,14 @@ export declare function computeAttentionWeights(state: PsycheState): AttentionWe
|
|
|
38
38
|
*
|
|
39
39
|
* Exploration is driven by:
|
|
40
40
|
* - High curiosity drive satisfaction (energy to explore)
|
|
41
|
-
* - High
|
|
42
|
-
* - High
|
|
43
|
-
* - Low CORT (not stressed)
|
|
41
|
+
* - High flow (exchange/novelty-seeking)
|
|
42
|
+
* - High order (coherent enough to venture out)
|
|
44
43
|
* - High safety (secure enough to take risks)
|
|
45
44
|
*
|
|
46
45
|
* Exploitation is driven by:
|
|
47
|
-
* -
|
|
46
|
+
* - Low order (disorder/stress)
|
|
48
47
|
* - Low safety drive satisfaction
|
|
49
|
-
* - Low
|
|
48
|
+
* - Low flow (no exchange motivation)
|
|
50
49
|
*/
|
|
51
50
|
export declare function computeExploreExploit(state: PsycheState): number;
|
|
52
51
|
/**
|