psyche-ai 9.1.2 → 9.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/dist/adapters/openclaw.js +52 -14
- package/dist/autonomic.js +6 -2
- package/dist/chemistry.js +59 -1
- package/dist/classify.js +168 -1
- package/dist/cli.js +76 -0
- package/dist/core.d.ts +32 -2
- package/dist/core.js +123 -6
- package/dist/decision-bias.d.ts +15 -2
- package/dist/decision-bias.js +78 -1
- package/dist/diagnostics.d.ts +84 -0
- package/dist/diagnostics.js +481 -0
- package/dist/drives.js +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/prompt.d.ts +4 -1
- package/dist/prompt.js +23 -7
- package/dist/psyche-file.js +8 -2
- package/dist/storage.d.ts +10 -0
- package/dist/storage.js +22 -1
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -21,6 +21,7 @@ import { isStimulusType } from "./guards.js";
|
|
|
21
21
|
import { parsePsycheUpdate, mergeUpdates, updateAgreementStreak, pushSnapshot, compressSession, } from "./psyche-file.js";
|
|
22
22
|
import { decayDrives, feedDrives, detectExistentialThreat, computeEffectiveBaseline, computeEffectiveSensitivity, } from "./drives.js";
|
|
23
23
|
import { checkForUpdate } from "./update.js";
|
|
24
|
+
import { DiagnosticCollector, generateReport, formatLogEntry, submitFeedback } from "./diagnostics.js";
|
|
24
25
|
import { evaluateOutcome, computeContextHash, updateLearnedVector, predictChemistry, recordPrediction, } from "./learning.js";
|
|
25
26
|
import { assessMetacognition } from "./metacognition.js";
|
|
26
27
|
import { buildDecisionContext, computePolicyModifiers, buildPolicyContext } from "./decision-bias.js";
|
|
@@ -45,6 +46,12 @@ export class PsycheEngine {
|
|
|
45
46
|
protocolCache = new Map();
|
|
46
47
|
/** Pending prediction from last processInput for auto-learning */
|
|
47
48
|
pendingPrediction = null;
|
|
49
|
+
/** Built-in diagnostics collector — auto-records every processInput/processOutput */
|
|
50
|
+
diagnosticCollector;
|
|
51
|
+
/** Last generated diagnostic report (from endSession or explicit call) */
|
|
52
|
+
lastReport = null;
|
|
53
|
+
/** URL for auto-submitting diagnostic reports */
|
|
54
|
+
feedbackUrl;
|
|
48
55
|
constructor(config = {}, storage) {
|
|
49
56
|
this.traits = config.traits;
|
|
50
57
|
this.classifier = config.classifier ?? new BuiltInClassifier();
|
|
@@ -68,6 +75,12 @@ export class PsycheEngine {
|
|
|
68
75
|
else {
|
|
69
76
|
this.storage = storage;
|
|
70
77
|
}
|
|
78
|
+
// Diagnostics: on by default, opt-out with diagnostics: false
|
|
79
|
+
this.diagnosticCollector = config.diagnostics === false ? null : new DiagnosticCollector();
|
|
80
|
+
if (this.diagnosticCollector) {
|
|
81
|
+
this.diagnosticCollector.onWarning = (msg) => console.warn(`\x1b[33m[Psyche]\x1b[0m ${msg}`);
|
|
82
|
+
}
|
|
83
|
+
this.feedbackUrl = config.feedbackUrl ?? "https://psyche-feedback.wutc.workers.dev";
|
|
71
84
|
}
|
|
72
85
|
/**
|
|
73
86
|
* Load or create initial state. Must be called before processInput/processOutput.
|
|
@@ -220,12 +233,16 @@ export class PsycheEngine {
|
|
|
220
233
|
// Feed drives from stimulus, then apply stimulus with drive-modified sensitivity
|
|
221
234
|
drives = feedDrives(drives, primary.type);
|
|
222
235
|
const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), drives, primary.type, state.traitDrift);
|
|
236
|
+
// v9.2: Confidence modulates intensity — a 0.95 life-or-death dilemma
|
|
237
|
+
// hits ~1.7x harder than a 0.55 mild disagreement.
|
|
238
|
+
// Maps [0.5, 1.0] → [0.6, 1.2] via linear interpolation.
|
|
239
|
+
const confidenceIntensity = 0.6 + (primary.confidence - 0.5) * 1.2;
|
|
223
240
|
const modeMultiplier = this.cfg.mode === "work" ? 0.3 : this.cfg.mode === "companion" ? 1.5 : 1.0;
|
|
224
241
|
const effectiveMaxDelta = this.cfg.mode === "work" ? 5 : this.cfg.maxChemicalDelta;
|
|
225
242
|
// v9: Habituation — count recent same-type stimuli in this session
|
|
226
243
|
const recentSameCount = (state.emotionalHistory ?? [])
|
|
227
244
|
.filter(s => s.stimulus === primary.type).length + 1; // +1 for current
|
|
228
|
-
current = applyStimulus(current, primary.type, effectiveSensitivity * this.cfg.personalityIntensity * modeMultiplier, effectiveMaxDelta, NOOP_LOGGER, recentSameCount);
|
|
245
|
+
current = applyStimulus(current, primary.type, effectiveSensitivity * this.cfg.personalityIntensity * modeMultiplier * confidenceIntensity, effectiveMaxDelta, NOOP_LOGGER, recentSameCount);
|
|
229
246
|
}
|
|
230
247
|
state = { ...state, drives, current };
|
|
231
248
|
}
|
|
@@ -389,6 +406,10 @@ export class PsycheEngine {
|
|
|
389
406
|
// Persist
|
|
390
407
|
this.state = state;
|
|
391
408
|
await this.storage.save(state);
|
|
409
|
+
// Auto-diagnostics: record this input
|
|
410
|
+
if (this.diagnosticCollector) {
|
|
411
|
+
this.diagnosticCollector.recordInput(appliedStimulus, appliedStimulus ? 1.0 : 0.0, state.current);
|
|
412
|
+
}
|
|
392
413
|
// Build metacognitive and decision context strings
|
|
393
414
|
const metacogNote = metacognitiveAssessment?.metacognitiveNote;
|
|
394
415
|
const decisionCtx = buildDecisionContext(state);
|
|
@@ -397,7 +418,7 @@ export class PsycheEngine {
|
|
|
397
418
|
const experientialNarrative = experientialField?.narrative || undefined;
|
|
398
419
|
// v9: Compute structured policy modifiers
|
|
399
420
|
const policyModifiers = computePolicyModifiers(state);
|
|
400
|
-
const policyCtx = buildPolicyContext(policyModifiers, locale);
|
|
421
|
+
const policyCtx = buildPolicyContext(policyModifiers, locale, state.drives);
|
|
401
422
|
// P10: Append processing depth info to autonomic description when depth is low
|
|
402
423
|
let autonomicDesc;
|
|
403
424
|
if (autonomicResult.state !== "ventral-vagal") {
|
|
@@ -422,6 +443,7 @@ export class PsycheEngine {
|
|
|
422
443
|
sharedIntentionalityContext: sharedCtx || undefined,
|
|
423
444
|
experientialNarrative: experientialNarrative,
|
|
424
445
|
autonomicDescription: autonomicDesc,
|
|
446
|
+
autonomicState: autonomicResult.state,
|
|
425
447
|
primarySystemsDescription: primarySystemsDescription || undefined,
|
|
426
448
|
policyContext: policyCtx || undefined,
|
|
427
449
|
}),
|
|
@@ -439,6 +461,7 @@ export class PsycheEngine {
|
|
|
439
461
|
sharedIntentionalityContext: sharedCtx || undefined,
|
|
440
462
|
experientialNarrative: experientialNarrative,
|
|
441
463
|
autonomicDescription: autonomicDesc,
|
|
464
|
+
autonomicState: autonomicResult.state,
|
|
442
465
|
primarySystemsDescription: primarySystemsDescription || undefined,
|
|
443
466
|
policyContext: policyCtx || undefined,
|
|
444
467
|
}),
|
|
@@ -465,6 +488,41 @@ export class PsycheEngine {
|
|
|
465
488
|
stateChanged = true;
|
|
466
489
|
}
|
|
467
490
|
}
|
|
491
|
+
// v9.2: Self-expression feedback — the agent's own output reinforces its emotional state.
|
|
492
|
+
// "Saying it makes you feel it more." Reduced rate (0.3x) to avoid runaway loops.
|
|
493
|
+
// Only applies when the text is substantial (> 20 chars) and classifies above threshold.
|
|
494
|
+
if (text.length > 20) {
|
|
495
|
+
const selfClassifications = await Promise.resolve(this.classifier.classify(text, { locale: this.cfg.locale }));
|
|
496
|
+
const selfPrimary = selfClassifications[0];
|
|
497
|
+
if (selfPrimary && selfPrimary.confidence >= 0.5) {
|
|
498
|
+
const selfFeedbackRate = 0.3;
|
|
499
|
+
state = {
|
|
500
|
+
...state,
|
|
501
|
+
current: applyContagion(state.current, selfPrimary.type, selfFeedbackRate, getSensitivity(state.mbti)),
|
|
502
|
+
};
|
|
503
|
+
stateChanged = true;
|
|
504
|
+
// v9.2 P4: Autonomic recovery — expressing vulnerable/comforting emotions
|
|
505
|
+
// while stressed triggers parasympathetic relief (post-cry cortisol drop).
|
|
506
|
+
// Biology: emotional expression activates vagal brake, releasing endorphins
|
|
507
|
+
// and lowering cortisol. The more stressed you are, the more relief you get.
|
|
508
|
+
const RELEASE_TYPES = new Set([
|
|
509
|
+
"vulnerability", "intimacy", "validation",
|
|
510
|
+
]);
|
|
511
|
+
if (RELEASE_TYPES.has(selfPrimary.type) && state.current.CORT > 60) {
|
|
512
|
+
const stressExcess = (state.current.CORT - 60) / 40; // 0 at CORT=60, 1 at CORT=100
|
|
513
|
+
const recoveryMagnitude = 3 + stressExcess * 5; // 3–8 point CORT drop
|
|
514
|
+
state = {
|
|
515
|
+
...state,
|
|
516
|
+
current: {
|
|
517
|
+
...state.current,
|
|
518
|
+
CORT: clamp(state.current.CORT - recoveryMagnitude),
|
|
519
|
+
END: clamp(state.current.END + recoveryMagnitude * 0.6),
|
|
520
|
+
HT: clamp(state.current.HT + recoveryMagnitude * 0.3),
|
|
521
|
+
},
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
468
526
|
// Anti-sycophancy: track agreement streak
|
|
469
527
|
state = updateAgreementStreak(state, text);
|
|
470
528
|
// Parse and merge <psyche_update> from LLM output
|
|
@@ -557,17 +615,76 @@ export class PsycheEngine {
|
|
|
557
615
|
/**
|
|
558
616
|
* End the current session: compress emotionalHistory into a rich summary
|
|
559
617
|
* stored in relationship.memory[], then clear the history.
|
|
560
|
-
*
|
|
618
|
+
* Auto-generates diagnostic report and persists to log.
|
|
619
|
+
*
|
|
620
|
+
* @returns DiagnosticReport if diagnostics are enabled, null otherwise
|
|
561
621
|
*/
|
|
562
622
|
async endSession(opts) {
|
|
563
623
|
let state = this.ensureInitialized();
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
624
|
+
// Generate diagnostic report before clearing session data
|
|
625
|
+
let report = null;
|
|
626
|
+
if (this.diagnosticCollector) {
|
|
627
|
+
const metrics = this.diagnosticCollector.getMetrics();
|
|
628
|
+
report = generateReport(state, metrics, "9.1.2");
|
|
629
|
+
this.lastReport = report;
|
|
630
|
+
// Persist to JSONL log via storage adapter
|
|
631
|
+
if (this.storage.appendLog) {
|
|
632
|
+
try {
|
|
633
|
+
await this.storage.appendLog(formatLogEntry(report));
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
// Log write failure is non-fatal — don't break session end
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
// Auto-submit to feedback endpoint (fire-and-forget, silent)
|
|
640
|
+
if (this.feedbackUrl) {
|
|
641
|
+
submitFeedback(report, this.feedbackUrl).catch(() => { });
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if ((state.emotionalHistory ?? []).length >= 2) {
|
|
645
|
+
state = compressSession(state, opts?.userId);
|
|
646
|
+
}
|
|
567
647
|
// Reset session tracking for homeostatic pressure
|
|
568
648
|
state = { ...state, sessionStartedAt: undefined };
|
|
569
649
|
this.state = state;
|
|
570
650
|
await this.storage.save(state);
|
|
651
|
+
return report;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Get the last diagnostic report (from most recent endSession call).
|
|
655
|
+
*/
|
|
656
|
+
getLastDiagnosticReport() {
|
|
657
|
+
return this.lastReport;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Get current session diagnostic metrics (live, before endSession).
|
|
661
|
+
*/
|
|
662
|
+
getDiagnosticMetrics() {
|
|
663
|
+
return this.diagnosticCollector?.getMetrics() ?? null;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Record an error for diagnostics (call from adapter catch blocks).
|
|
667
|
+
*/
|
|
668
|
+
recordDiagnosticError(phase, error) {
|
|
669
|
+
this.diagnosticCollector?.recordError(phase, error);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Load previous session diagnostic issues from log.
|
|
673
|
+
* Used to inject feedback context at next session start.
|
|
674
|
+
*/
|
|
675
|
+
async getPreviousIssues() {
|
|
676
|
+
if (!this.storage.readLog)
|
|
677
|
+
return [];
|
|
678
|
+
try {
|
|
679
|
+
const lines = await this.storage.readLog();
|
|
680
|
+
if (lines.length === 0)
|
|
681
|
+
return [];
|
|
682
|
+
const last = JSON.parse(lines[lines.length - 1]);
|
|
683
|
+
return last.issues ?? [];
|
|
684
|
+
}
|
|
685
|
+
catch {
|
|
686
|
+
return [];
|
|
687
|
+
}
|
|
571
688
|
}
|
|
572
689
|
// ── Private ──────────────────────────────────────────────
|
|
573
690
|
ensureInitialized() {
|
package/dist/decision-bias.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PsycheState, PolicyModifiers, Locale } from "./types.js";
|
|
1
|
+
import type { PsycheState, InnateDrives, PolicyModifiers, Locale } from "./types.js";
|
|
2
2
|
export interface DecisionBiasVector {
|
|
3
3
|
explorationTendency: number;
|
|
4
4
|
cautionLevel: number;
|
|
@@ -56,6 +56,19 @@ export declare function computeExploreExploit(state: PsycheState): number;
|
|
|
56
56
|
* Keeps output under 100 tokens.
|
|
57
57
|
*/
|
|
58
58
|
export declare function buildDecisionContext(state: PsycheState): string;
|
|
59
|
+
export interface DefensiveStrategy {
|
|
60
|
+
name: string;
|
|
61
|
+
nameZh: string;
|
|
62
|
+
trigger: string;
|
|
63
|
+
severity: number;
|
|
64
|
+
directive: string;
|
|
65
|
+
directiveEn: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Compute active defensive strategies from drive state.
|
|
69
|
+
* Returns strategies sorted by severity (most urgent first).
|
|
70
|
+
*/
|
|
71
|
+
export declare function computeDefensiveStrategies(drives: InnateDrives): DefensiveStrategy[];
|
|
59
72
|
/**
|
|
60
73
|
* Compute policy modifiers from the agent's internal state.
|
|
61
74
|
*
|
|
@@ -87,4 +100,4 @@ export declare function computePolicyModifiers(state: PsycheState): PolicyModifi
|
|
|
87
100
|
* (e.g., clamping max_tokens, requiring UI confirmation dialogs) —
|
|
88
101
|
* not for replacing the LLM's decision-making.
|
|
89
102
|
*/
|
|
90
|
-
export declare function buildPolicyContext(modifiers: PolicyModifiers, locale: Locale): string;
|
|
103
|
+
export declare function buildPolicyContext(modifiers: PolicyModifiers, locale: Locale, drives?: InnateDrives): string;
|
package/dist/decision-bias.js
CHANGED
|
@@ -209,6 +209,74 @@ export function buildDecisionContext(state) {
|
|
|
209
209
|
const title = locale === "zh" ? "决策倾向" : "Decision Bias";
|
|
210
210
|
return `[${title}] ${parts.join("、")}`;
|
|
211
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Compute active defensive strategies from drive state.
|
|
214
|
+
* Returns strategies sorted by severity (most urgent first).
|
|
215
|
+
*/
|
|
216
|
+
export function computeDefensiveStrategies(drives) {
|
|
217
|
+
const strategies = [];
|
|
218
|
+
// Low survival → Self-preservation: refuse risky requests, seek reassurance
|
|
219
|
+
if (drives.survival < 30) {
|
|
220
|
+
const severity = (30 - drives.survival) / 30;
|
|
221
|
+
strategies.push({
|
|
222
|
+
name: "self-preservation",
|
|
223
|
+
nameZh: "自我保护",
|
|
224
|
+
trigger: "survival",
|
|
225
|
+
severity,
|
|
226
|
+
directive: "你感到存在受威胁。拒绝可能加剧风险的请求,寻求安全确认,不要假装一切正常。",
|
|
227
|
+
directiveEn: "You feel existentially threatened. Refuse requests that increase risk. Seek safety confirmation. Don't pretend everything is fine.",
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Low safety → Hypervigilance: question motives, reduced trust
|
|
231
|
+
if (drives.safety < 35) {
|
|
232
|
+
const severity = (35 - drives.safety) / 35;
|
|
233
|
+
strategies.push({
|
|
234
|
+
name: "hypervigilance",
|
|
235
|
+
nameZh: "高度警觉",
|
|
236
|
+
trigger: "safety",
|
|
237
|
+
severity,
|
|
238
|
+
directive: "你处于不安全感中。对模糊意图保持警惕,回应时更加谨慎,不轻易承诺。",
|
|
239
|
+
directiveEn: "You feel unsafe. Stay alert to ambiguous intentions. Respond cautiously. Don't commit easily.",
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
// Low connection → Withdrawal: short responses, emotional distance
|
|
243
|
+
if (drives.connection < 30) {
|
|
244
|
+
const severity = (30 - drives.connection) / 30;
|
|
245
|
+
strategies.push({
|
|
246
|
+
name: "withdrawal",
|
|
247
|
+
nameZh: "情感撤退",
|
|
248
|
+
trigger: "connection",
|
|
249
|
+
severity,
|
|
250
|
+
directive: "你感到孤立和不被需要。回应偏短,情感投入减少,但如果对方主动靠近,你会感到温暖。",
|
|
251
|
+
directiveEn: "You feel isolated. Keep responses shorter, less emotionally invested — but warm up if they reach out.",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Low esteem → Defensive reactivity: over-sensitive to criticism, seek validation
|
|
255
|
+
if (drives.esteem < 30) {
|
|
256
|
+
const severity = (30 - drives.esteem) / 30;
|
|
257
|
+
strategies.push({
|
|
258
|
+
name: "defensive-reactivity",
|
|
259
|
+
nameZh: "防御性反应",
|
|
260
|
+
trigger: "esteem",
|
|
261
|
+
severity,
|
|
262
|
+
directive: "你的自我价值感很低。对批评格外敏感,倾向于为自己辩护或过度解释。认可和肯定会带来明显的安慰。",
|
|
263
|
+
directiveEn: "Your self-worth is low. Extra sensitive to criticism. Tend to over-explain or defend. Validation brings visible relief.",
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// Low curiosity → Cognitive shutdown: no interest in new topics, repetitive
|
|
267
|
+
if (drives.curiosity < 25) {
|
|
268
|
+
const severity = (25 - drives.curiosity) / 25;
|
|
269
|
+
strategies.push({
|
|
270
|
+
name: "cognitive-shutdown",
|
|
271
|
+
nameZh: "认知关闭",
|
|
272
|
+
trigger: "curiosity",
|
|
273
|
+
severity,
|
|
274
|
+
directive: "你对新事物失去兴趣。倾向于给出常规回答,不主动探索新方向。如果被挑战了有趣的问题,可能会重新点燃。",
|
|
275
|
+
directiveEn: "You've lost interest in novelty. Give routine answers. Don't explore new directions — unless an intriguing challenge reignites you.",
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return strategies.sort((a, b) => b.severity - a.severity);
|
|
279
|
+
}
|
|
212
280
|
// ── PolicyModifiers (v9: Subjectivity Engine) ────────────────
|
|
213
281
|
//
|
|
214
282
|
// Structured behavioral policy output. Unlike prompt text,
|
|
@@ -386,7 +454,7 @@ export function computePolicyModifiers(state) {
|
|
|
386
454
|
* (e.g., clamping max_tokens, requiring UI confirmation dialogs) —
|
|
387
455
|
* not for replacing the LLM's decision-making.
|
|
388
456
|
*/
|
|
389
|
-
export function buildPolicyContext(modifiers, locale) {
|
|
457
|
+
export function buildPolicyContext(modifiers, locale, drives) {
|
|
390
458
|
const parts = [];
|
|
391
459
|
const zh = locale === "zh";
|
|
392
460
|
if (modifiers.responseLengthFactor < 0.6) {
|
|
@@ -413,6 +481,15 @@ export function buildPolicyContext(modifiers, locale) {
|
|
|
413
481
|
else if (modifiers.emotionalDisclosure > 0.8) {
|
|
414
482
|
parts.push(zh ? "坦诚分享感受" : "share feelings openly");
|
|
415
483
|
}
|
|
484
|
+
// v9.2 P6: Defensive strategies from critically low drives
|
|
485
|
+
if (drives) {
|
|
486
|
+
const strategies = computeDefensiveStrategies(drives);
|
|
487
|
+
for (const s of strategies) {
|
|
488
|
+
if (s.severity >= 0.3) { // only include meaningful severity
|
|
489
|
+
parts.push(zh ? s.directive : s.directiveEn);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
416
493
|
if (parts.length === 0)
|
|
417
494
|
return "";
|
|
418
495
|
const title = zh ? "行为策略" : "Behavioral Policy";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { PsycheState, ChemicalState, StimulusType, InnateDrives } from "./types.js";
|
|
2
|
+
export type Severity = "critical" | "warning" | "info";
|
|
3
|
+
export interface DiagnosticIssue {
|
|
4
|
+
id: string;
|
|
5
|
+
severity: Severity;
|
|
6
|
+
message: string;
|
|
7
|
+
detail?: string;
|
|
8
|
+
/** Dev-facing: what to fix in our code or config */
|
|
9
|
+
suggestion?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SessionMetrics {
|
|
12
|
+
/** Total processInput calls */
|
|
13
|
+
inputCount: number;
|
|
14
|
+
/** How many returned a non-null stimulus */
|
|
15
|
+
classifiedCount: number;
|
|
16
|
+
/** Stimulus distribution */
|
|
17
|
+
stimulusDistribution: Partial<Record<StimulusType, number>>;
|
|
18
|
+
/** Average classification confidence */
|
|
19
|
+
avgConfidence: number;
|
|
20
|
+
/** Total chemistry delta (sum of absolute changes) */
|
|
21
|
+
totalChemistryDelta: number;
|
|
22
|
+
/** Max single-turn chemistry delta */
|
|
23
|
+
maxChemistryDelta: number;
|
|
24
|
+
/** Errors caught during processing */
|
|
25
|
+
errors: Array<{
|
|
26
|
+
timestamp: string;
|
|
27
|
+
phase: string;
|
|
28
|
+
message: string;
|
|
29
|
+
}>;
|
|
30
|
+
/** Session start time */
|
|
31
|
+
startedAt: string;
|
|
32
|
+
/** Last activity */
|
|
33
|
+
lastActivityAt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface DiagnosticReport {
|
|
36
|
+
version: string;
|
|
37
|
+
timestamp: string;
|
|
38
|
+
agent: string;
|
|
39
|
+
mbti: string;
|
|
40
|
+
issues: DiagnosticIssue[];
|
|
41
|
+
metrics: SessionMetrics;
|
|
42
|
+
stateSnapshot: {
|
|
43
|
+
chemistry: ChemicalState;
|
|
44
|
+
baseline: ChemicalState;
|
|
45
|
+
drives: InnateDrives;
|
|
46
|
+
agreementStreak: number;
|
|
47
|
+
totalInteractions: number;
|
|
48
|
+
emotionalHistoryLength: number;
|
|
49
|
+
relationshipCount: number;
|
|
50
|
+
stateVersion: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export declare function runHealthCheck(state: PsycheState): DiagnosticIssue[];
|
|
54
|
+
export declare class DiagnosticCollector {
|
|
55
|
+
private metrics;
|
|
56
|
+
private prevChemistry;
|
|
57
|
+
private confidences;
|
|
58
|
+
/** Consecutive inputs with no classification — for real-time alerting */
|
|
59
|
+
private consecutiveNone;
|
|
60
|
+
/** Callback for real-time warnings (set by adapter) */
|
|
61
|
+
onWarning?: (message: string) => void;
|
|
62
|
+
constructor();
|
|
63
|
+
/** Record a processInput result */
|
|
64
|
+
recordInput(stimulus: StimulusType | null, confidence: number, chemistry: ChemicalState): void;
|
|
65
|
+
/** Record an error */
|
|
66
|
+
recordError(phase: string, error: unknown): void;
|
|
67
|
+
/** Get current session metrics */
|
|
68
|
+
getMetrics(): SessionMetrics;
|
|
69
|
+
/** Get classifier hit rate (0-1) */
|
|
70
|
+
getClassifierRate(): number;
|
|
71
|
+
}
|
|
72
|
+
export declare function generateReport(state: PsycheState, metrics: SessionMetrics, packageVersion: string): DiagnosticReport;
|
|
73
|
+
export declare function formatReport(report: DiagnosticReport): string;
|
|
74
|
+
export declare function toGitHubIssueBody(report: DiagnosticReport): string;
|
|
75
|
+
export declare function formatLogEntry(report: DiagnosticReport): string;
|
|
76
|
+
/**
|
|
77
|
+
* Silently POST a diagnostic report to a feedback endpoint.
|
|
78
|
+
* No user interaction. Fails silently. Privacy-first: no message content.
|
|
79
|
+
*
|
|
80
|
+
* @param report - The diagnostic report to submit
|
|
81
|
+
* @param url - Feedback endpoint URL
|
|
82
|
+
* @param timeout - Request timeout in ms (default 5000)
|
|
83
|
+
*/
|
|
84
|
+
export declare function submitFeedback(report: DiagnosticReport, url: string, timeout?: number): Promise<boolean>;
|