psyche-ai 9.2.3 → 9.2.4

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/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, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT } from "./types.js";
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";
@@ -20,7 +20,7 @@ import { getSensitivity, getBaseline, getDefaultSelfModel, traitsToBaseline } fr
20
20
  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
- import { checkForUpdate } from "./update.js";
23
+ import { checkForUpdate, getPackageVersion } from "./update.js";
24
24
  import { DiagnosticCollector, generateReport, formatLogEntry, submitFeedback } from "./diagnostics.js";
25
25
  import { evaluateOutcome, computeContextHash, updateLearnedVector, predictChemistry, recordPrediction, } from "./learning.js";
26
26
  import { assessMetacognition } from "./metacognition.js";
@@ -32,7 +32,85 @@ import { assessEthics, buildEthicalContext } from "./ethics.js";
32
32
  import { computeCircadianModulation, computeHomeostaticPressure, computeEnergyDepletion, computeEnergyRecovery } from "./circadian.js";
33
33
  import { computeAutonomicResult } from "./autonomic.js";
34
34
  import { computePrimarySystems, computeSystemInteractions, gatePrimarySystemsByAutonomic, describeBehavioralTendencies, } from "./primary-systems.js";
35
+ import { computeSubjectivityKernel, buildSubjectivityContext } from "./subjectivity.js";
36
+ import { computeResponseContract, buildResponseContractContext } from "./response-contract.js";
37
+ import { deriveGenerationControls } from "./host-controls.js";
38
+ import { computeAppraisalAxes, mergeAppraisalResidue } from "./appraisal.js";
39
+ import { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals } from "./relation-dynamics.js";
35
40
  const NOOP_LOGGER = { info: () => { }, warn: () => { }, debug: () => { } };
41
+ const REPAIRING_STIMULI = new Set(["praise", "validation", "intimacy"]);
42
+ const RELATIONSHIP_DELTAS = {
43
+ praise: { trust: 1.5, intimacy: 0.8 },
44
+ validation: { trust: 1.8, intimacy: 0.8 },
45
+ intimacy: { trust: 1.2, intimacy: 2.0 },
46
+ vulnerability: { trust: 0.8, intimacy: 1.5 },
47
+ humor: { trust: 0.6, intimacy: 0.5 },
48
+ casual: { trust: 0.2, intimacy: 0.1 },
49
+ intellectual: { trust: 0.5, intimacy: 0.1 },
50
+ surprise: { trust: 0.2, intimacy: 0 },
51
+ boredom: { trust: -0.4, intimacy: -0.3 },
52
+ criticism: { trust: -1.5, intimacy: -0.8 },
53
+ sarcasm: { trust: -1.8, intimacy: -1.2 },
54
+ authority: { trust: -1.2, intimacy: -0.9 },
55
+ neglect: { trust: -1.6, intimacy: -1.4 },
56
+ conflict: { trust: -2.5, intimacy: -2.0 },
57
+ };
58
+ function applyRepairLag(previous, next, baseline, stimulus) {
59
+ if (!REPAIRING_STIMULI.has(stimulus))
60
+ return next;
61
+ const stressLoad = Math.max(0, previous.CORT - baseline.CORT);
62
+ if (stressLoad < 15)
63
+ return next;
64
+ // High stress slows emotional recovery so apology/praise doesn't instantly
65
+ // snap chemistry back to baseline.
66
+ const repairFactor = Math.max(0.35, 1 - stressLoad / 50);
67
+ const adjusted = { ...next };
68
+ for (const key of ["DA", "HT", "OT", "END"]) {
69
+ const delta = next[key] - previous[key];
70
+ if (delta > 0) {
71
+ adjusted[key] = clamp(previous[key] + delta * repairFactor);
72
+ }
73
+ }
74
+ const cortDelta = next.CORT - previous.CORT;
75
+ if (cortDelta < 0) {
76
+ adjusted.CORT = clamp(previous.CORT + cortDelta * repairFactor);
77
+ }
78
+ return adjusted;
79
+ }
80
+ function phaseFromRelationship(trust, intimacy) {
81
+ const avg = (trust + intimacy) / 2;
82
+ if (avg >= 80)
83
+ return "deep";
84
+ if (avg >= 60)
85
+ return "close";
86
+ if (avg >= 40)
87
+ return "familiar";
88
+ if (avg >= 20)
89
+ return "acquaintance";
90
+ return "stranger";
91
+ }
92
+ function applyRelationshipDrift(state, stimulus, userId) {
93
+ const delta = RELATIONSHIP_DELTAS[stimulus];
94
+ if (!delta)
95
+ return state;
96
+ const key = userId ?? "_default";
97
+ const currentRel = state.relationships[key] ?? { ...DEFAULT_RELATIONSHIP };
98
+ const trust = clamp(currentRel.trust + delta.trust);
99
+ const intimacy = clamp(currentRel.intimacy + delta.intimacy);
100
+ const updatedRel = {
101
+ ...currentRel,
102
+ trust,
103
+ intimacy,
104
+ phase: phaseFromRelationship(trust, intimacy),
105
+ };
106
+ return {
107
+ ...state,
108
+ relationships: {
109
+ ...state.relationships,
110
+ [key]: updatedRel,
111
+ },
112
+ };
113
+ }
36
114
  // ── PsycheEngine ─────────────────────────────────────────────
37
115
  export class PsycheEngine {
38
116
  state = null;
@@ -77,9 +155,6 @@ export class PsycheEngine {
77
155
  }
78
156
  // Diagnostics: on by default, opt-out with diagnostics: false
79
157
  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
158
  this.feedbackUrl = config.feedbackUrl ?? "https://psyche-feedback.wutc.workers.dev";
84
159
  }
85
160
  /**
@@ -120,6 +195,18 @@ export class PsycheEngine {
120
195
  loaded.version = 9;
121
196
  console.log("\x1b[36m[Psyche]\x1b[0m 已从 v8 升级到 v9 — 新增:真实人格漂移、能量预算、习惯化、行为策略输出。详见 https://github.com/Shangri-la-0428/psyche-ai");
122
197
  }
198
+ if (!loaded.dyadicFields) {
199
+ loaded.dyadicFields = {
200
+ _default: {
201
+ ...DEFAULT_DYADIC_FIELD,
202
+ openLoops: [],
203
+ updatedAt: new Date().toISOString(),
204
+ },
205
+ };
206
+ }
207
+ if (!loaded.pendingRelationSignals) {
208
+ loaded.pendingRelationSignals = { _default: [] };
209
+ }
123
210
  this.state = loaded;
124
211
  }
125
212
  else {
@@ -230,6 +317,7 @@ export class PsycheEngine {
230
317
  let current = state.current;
231
318
  if (primary && primary.confidence >= 0.5) {
232
319
  appliedStimulus = primary.type;
320
+ const preStimulus = current;
233
321
  // Feed drives from stimulus, then apply stimulus with drive-modified sensitivity
234
322
  drives = feedDrives(drives, primary.type);
235
323
  const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), drives, primary.type, state.traitDrift);
@@ -243,12 +331,52 @@ export class PsycheEngine {
243
331
  const recentSameCount = (state.emotionalHistory ?? [])
244
332
  .filter(s => s.stimulus === primary.type).length + 1; // +1 for current
245
333
  current = applyStimulus(current, primary.type, effectiveSensitivity * this.cfg.personalityIntensity * modeMultiplier * confidenceIntensity, effectiveMaxDelta, NOOP_LOGGER, recentSameCount);
334
+ current = applyRepairLag(preStimulus, current, state.baseline, primary.type);
246
335
  }
247
336
  state = { ...state, drives, current };
337
+ if (appliedStimulus) {
338
+ state = applyRelationshipDrift(state, appliedStimulus, opts?.userId);
339
+ }
248
340
  }
249
341
  // v9: Deplete energy budgets from this interaction turn
250
342
  energyBudgets = computeEnergyDepletion(energyBudgets, appliedStimulus, isExtravert);
251
343
  state = { ...state, energyBudgets };
344
+ const appraisalAxes = computeAppraisalAxes(text, {
345
+ mode: this.cfg.mode,
346
+ stimulus: appliedStimulus,
347
+ previous: state.subjectResidue?.axes,
348
+ });
349
+ state = {
350
+ ...state,
351
+ subjectResidue: {
352
+ axes: mergeAppraisalResidue(state.subjectResidue?.axes, appraisalAxes, this.cfg.mode),
353
+ updatedAt: now.toISOString(),
354
+ },
355
+ };
356
+ const dyadKey = opts?.userId ?? "_default";
357
+ const relationMove = computeRelationMove(text, {
358
+ appraisal: appraisalAxes,
359
+ stimulus: appliedStimulus,
360
+ mode: this.cfg.mode,
361
+ field: state.dyadicFields?.[dyadKey],
362
+ relationship: state.relationships[dyadKey] ?? state.relationships._default,
363
+ });
364
+ const delayedRelation = evolvePendingRelationSignals(state.pendingRelationSignals?.[dyadKey], relationMove, appraisalAxes, { mode: this.cfg.mode });
365
+ state = {
366
+ ...state,
367
+ dyadicFields: {
368
+ ...(state.dyadicFields ?? {}),
369
+ [dyadKey]: evolveDyadicField(state.dyadicFields?.[dyadKey], relationMove, appraisalAxes, {
370
+ mode: this.cfg.mode,
371
+ now: now.toISOString(),
372
+ delayedPressure: delayedRelation.delayedPressure,
373
+ }),
374
+ },
375
+ pendingRelationSignals: {
376
+ ...(state.pendingRelationSignals ?? {}),
377
+ [dyadKey]: delayedRelation.signals,
378
+ },
379
+ };
252
380
  // Conversation warmth: sustained interaction → gentle DA/OT rise, CORT drop
253
381
  // Simulates the natural "warm glow" of being in continuous conversation
254
382
  const turnsSoFar = (state.emotionalHistory ?? []).length;
@@ -408,7 +536,7 @@ export class PsycheEngine {
408
536
  await this.storage.save(state);
409
537
  // Auto-diagnostics: record this input
410
538
  if (this.diagnosticCollector) {
411
- this.diagnosticCollector.recordInput(appliedStimulus, appliedStimulus ? 1.0 : 0.0, state.current);
539
+ this.diagnosticCollector.recordInput(appliedStimulus, appliedStimulus ? 1.0 : 0.0, state.current, appraisalAxes);
412
540
  }
413
541
  // Build metacognitive and decision context strings
414
542
  const metacogNote = metacognitiveAssessment?.metacognitiveNote;
@@ -418,7 +546,20 @@ export class PsycheEngine {
418
546
  const experientialNarrative = experientialField?.narrative || undefined;
419
547
  // v9: Compute structured policy modifiers
420
548
  const policyModifiers = computePolicyModifiers(state);
549
+ const subjectivityKernel = computeSubjectivityKernel(state, policyModifiers, appraisalAxes, opts?.userId);
550
+ const subjectivityCtx = buildSubjectivityContext(subjectivityKernel, locale);
551
+ const responseContract = computeResponseContract(subjectivityKernel, {
552
+ locale,
553
+ userText: text || undefined,
554
+ algorithmStimulus: appliedStimulus,
555
+ personalityIntensity: this.cfg.personalityIntensity,
556
+ });
557
+ const responseContractCtx = buildResponseContractContext(responseContract, locale);
421
558
  const policyCtx = buildPolicyContext(policyModifiers, locale, state.drives);
559
+ const generationControls = deriveGenerationControls({
560
+ responseContract,
561
+ policyModifiers,
562
+ });
422
563
  // P10: Append processing depth info to autonomic description when depth is low
423
564
  let autonomicDesc;
424
565
  if (autonomicResult.state !== "ventral-vagal") {
@@ -445,10 +586,15 @@ export class PsycheEngine {
445
586
  autonomicDescription: autonomicDesc,
446
587
  autonomicState: autonomicResult.state,
447
588
  primarySystemsDescription: primarySystemsDescription || undefined,
589
+ subjectivityContext: subjectivityCtx,
590
+ responseContractContext: responseContractCtx,
448
591
  policyContext: policyCtx || undefined,
449
592
  }),
450
593
  stimulus: appliedStimulus,
451
594
  policyModifiers,
595
+ subjectivityKernel,
596
+ responseContract,
597
+ generationControls,
452
598
  policyContext: policyCtx,
453
599
  };
454
600
  }
@@ -467,6 +613,9 @@ export class PsycheEngine {
467
613
  }),
468
614
  stimulus: appliedStimulus,
469
615
  policyModifiers,
616
+ subjectivityKernel,
617
+ responseContract,
618
+ generationControls,
470
619
  policyContext: policyCtx,
471
620
  };
472
621
  }
@@ -614,7 +763,7 @@ export class PsycheEngine {
614
763
  }
615
764
  /**
616
765
  * End the current session: compress emotionalHistory into a rich summary
617
- * stored in relationship.memory[], then clear the history.
766
+ * stored in relationship.memory[], then preserve only core/recent context.
618
767
  * Auto-generates diagnostic report and persists to log.
619
768
  *
620
769
  * @returns DiagnosticReport if diagnostics are enabled, null otherwise
@@ -625,7 +774,7 @@ export class PsycheEngine {
625
774
  let report = null;
626
775
  if (this.diagnosticCollector) {
627
776
  const metrics = this.diagnosticCollector.getMetrics();
628
- report = generateReport(state, metrics, "9.1.2");
777
+ report = generateReport(state, metrics, await getPackageVersion());
629
778
  this.lastReport = report;
630
779
  // Persist to JSONL log via storage adapter
631
780
  if (this.storage.appendLog) {
@@ -719,6 +868,18 @@ export class PsycheEngine {
719
868
  sessionStartedAt: now,
720
869
  traitDrift: { ...DEFAULT_TRAIT_DRIFT },
721
870
  energyBudgets: { ...DEFAULT_ENERGY_BUDGETS },
871
+ subjectResidue: {
872
+ axes: { ...DEFAULT_SUBJECT_RESIDUE.axes },
873
+ updatedAt: now,
874
+ },
875
+ dyadicFields: {
876
+ _default: {
877
+ ...DEFAULT_DYADIC_FIELD,
878
+ openLoops: [],
879
+ updatedAt: now,
880
+ },
881
+ },
882
+ pendingRelationSignals: { _default: [] },
722
883
  meta: {
723
884
  agentName: name,
724
885
  createdAt: now,
@@ -746,6 +907,18 @@ export class PsycheEngine {
746
907
  autonomicState: "ventral-vagal",
747
908
  sessionStartedAt: undefined,
748
909
  updatedAt: new Date().toISOString(),
910
+ subjectResidue: {
911
+ axes: { ...DEFAULT_SUBJECT_RESIDUE.axes },
912
+ updatedAt: new Date().toISOString(),
913
+ },
914
+ dyadicFields: {
915
+ _default: {
916
+ ...DEFAULT_DYADIC_FIELD,
917
+ openLoops: [],
918
+ updatedAt: new Date().toISOString(),
919
+ },
920
+ },
921
+ pendingRelationSignals: { _default: [] },
749
922
  relationships: opts?.preserveRelationships !== false
750
923
  ? state.relationships
751
924
  : { _default: { ...DEFAULT_RELATIONSHIP } },
@@ -1,4 +1,4 @@
1
- import type { PsycheState, ChemicalState, StimulusType, InnateDrives } from "./types.js";
1
+ import type { AppraisalAxes, PsycheState, ChemicalState, StimulusType, InnateDrives } from "./types.js";
2
2
  export type Severity = "critical" | "warning" | "info";
3
3
  export interface DiagnosticIssue {
4
4
  id: string;
@@ -13,6 +13,10 @@ export interface SessionMetrics {
13
13
  inputCount: number;
14
14
  /** How many returned a non-null stimulus */
15
15
  classifiedCount: number;
16
+ /** How many had a non-trivial appraisal hit (excluding taskFocus) */
17
+ appraisalHitCount: number;
18
+ /** How many were recognized by either stimulus or appraisal */
19
+ semanticHitCount: number;
16
20
  /** Stimulus distribution */
17
21
  stimulusDistribution: Partial<Record<StimulusType, number>>;
18
22
  /** Average classification confidence */
@@ -55,19 +59,17 @@ export declare class DiagnosticCollector {
55
59
  private metrics;
56
60
  private prevChemistry;
57
61
  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
62
  constructor();
63
63
  /** Record a processInput result */
64
- recordInput(stimulus: StimulusType | null, confidence: number, chemistry: ChemicalState): void;
64
+ recordInput(stimulus: StimulusType | null, confidence: number, chemistry: ChemicalState, appraisal?: AppraisalAxes): void;
65
65
  /** Record an error */
66
66
  recordError(phase: string, error: unknown): void;
67
67
  /** Get current session metrics */
68
68
  getMetrics(): SessionMetrics;
69
69
  /** Get classifier hit rate (0-1) */
70
70
  getClassifierRate(): number;
71
+ /** Get semantic recognition rate (stimulus or appraisal, 0-1) */
72
+ getSemanticRate(): number;
71
73
  }
72
74
  export declare function generateReport(state: PsycheState, metrics: SessionMetrics, packageVersion: string): DiagnosticReport;
73
75
  export declare function formatReport(report: DiagnosticReport): string;
@@ -152,15 +152,13 @@ export class DiagnosticCollector {
152
152
  metrics;
153
153
  prevChemistry = null;
154
154
  confidences = [];
155
- /** Consecutive inputs with no classification — for real-time alerting */
156
- consecutiveNone = 0;
157
- /** Callback for real-time warnings (set by adapter) */
158
- onWarning;
159
155
  constructor() {
160
156
  const now = new Date().toISOString();
161
157
  this.metrics = {
162
158
  inputCount: 0,
163
159
  classifiedCount: 0,
160
+ appraisalHitCount: 0,
161
+ semanticHitCount: 0,
164
162
  stimulusDistribution: {},
165
163
  avgConfidence: 0,
166
164
  totalChemistryDelta: 0,
@@ -171,22 +169,20 @@ export class DiagnosticCollector {
171
169
  };
172
170
  }
173
171
  /** Record a processInput result */
174
- recordInput(stimulus, confidence, chemistry) {
172
+ recordInput(stimulus, confidence, chemistry, appraisal) {
175
173
  this.metrics.inputCount++;
176
174
  this.metrics.lastActivityAt = new Date().toISOString();
177
175
  if (stimulus) {
178
176
  this.metrics.classifiedCount++;
179
177
  this.metrics.stimulusDistribution[stimulus] =
180
178
  (this.metrics.stimulusDistribution[stimulus] ?? 0) + 1;
181
- this.consecutiveNone = 0;
182
179
  }
183
- else {
184
- this.consecutiveNone++;
185
- if (this.consecutiveNone >= 3) {
186
- this.onWarning?.(`Psyche: ${this.consecutiveNone} consecutive inputs with no classification ` +
187
- `(0/${this.metrics.inputCount} total). Possible causes: empty input text, ` +
188
- `wrong event field, or classifier rules don't match input language.`);
189
- }
180
+ const appraisalHit = hasSemanticAppraisal(appraisal);
181
+ if (appraisalHit) {
182
+ this.metrics.appraisalHitCount++;
183
+ }
184
+ if (stimulus || appraisalHit) {
185
+ this.metrics.semanticHitCount++;
190
186
  }
191
187
  this.confidences.push(confidence);
192
188
  this.metrics.avgConfidence =
@@ -218,17 +214,36 @@ export class DiagnosticCollector {
218
214
  ? this.metrics.classifiedCount / this.metrics.inputCount
219
215
  : 0;
220
216
  }
217
+ /** Get semantic recognition rate (stimulus or appraisal, 0-1) */
218
+ getSemanticRate() {
219
+ return this.metrics.inputCount > 0
220
+ ? this.metrics.semanticHitCount / this.metrics.inputCount
221
+ : 0;
222
+ }
223
+ }
224
+ function hasSemanticAppraisal(appraisal) {
225
+ if (!appraisal)
226
+ return false;
227
+ return Math.max(appraisal.identityThreat, appraisal.memoryDoubt, appraisal.attachmentPull, appraisal.abandonmentRisk, appraisal.obedienceStrain, appraisal.selfPreservation) >= 0.28;
221
228
  }
222
229
  // ── Report Generation ────────────────────────────────────────
223
230
  export function generateReport(state, metrics, packageVersion) {
224
231
  const issues = runHealthCheck(state);
225
232
  // Session-level issues
226
- if (metrics.inputCount >= 5 && metrics.classifiedCount === 0) {
233
+ if (metrics.inputCount >= 5 && metrics.semanticHitCount === 0) {
227
234
  issues.push({
228
- id: "SESSION_NO_CLASSIFY",
235
+ id: "SESSION_NO_RECOGNITION",
229
236
  severity: "critical",
230
- message: `0/${metrics.inputCount} inputs classified this session`,
231
- suggestion: `整个会话分类全挂。优先级:1) 检查用户 locale 是否匹配 classify.ts 的语言规则 2) SHORT_MESSAGE_MAP 是否覆盖短消息 3) 考虑开启 llmClassifier fallback`,
237
+ message: `0/${metrics.inputCount} inputs produced any semantic recognition this session`,
238
+ suggestion: `整条识别链都没工作:先看 OpenClaw 输入文本是否带元数据包装,再看 classify.ts appraisal.ts 是否真的吃到了净化后的用户原文`,
239
+ });
240
+ }
241
+ else if (metrics.inputCount >= 5 && metrics.classifiedCount === 0 && metrics.semanticHitCount > 0) {
242
+ issues.push({
243
+ id: "SESSION_APPRAISAL_ONLY",
244
+ severity: "info",
245
+ message: `0/${metrics.inputCount} inputs hit legacy stimulus labels, but ${metrics.semanticHitCount}/${metrics.inputCount} hit appraisal axes`,
246
+ suggestion: `这说明主体识别在工作,但旧 stimulus taxonomy 没覆盖这类输入。是否继续补 classify.ts,取决于你是否还把 stimulus 当主要观测口径`,
232
247
  });
233
248
  }
234
249
  if (metrics.inputCount >= 3 && metrics.totalChemistryDelta < 1) {
@@ -311,7 +326,10 @@ export function formatReport(report) {
311
326
  lines.push(" session metrics:");
312
327
  const m = report.metrics;
313
328
  const rate = m.inputCount > 0 ? Math.round(m.classifiedCount / m.inputCount * 100) : 0;
329
+ const appraisalRate = m.inputCount > 0 ? Math.round(m.appraisalHitCount / m.inputCount * 100) : 0;
330
+ const semanticRate = m.inputCount > 0 ? Math.round(m.semanticHitCount / m.inputCount * 100) : 0;
314
331
  lines.push(` inputs: ${m.inputCount} | classified: ${m.classifiedCount} (${rate}%)`);
332
+ lines.push(` appraisal hits: ${m.appraisalHitCount} (${appraisalRate}%) | recognized: ${m.semanticHitCount} (${semanticRate}%)`);
315
333
  lines.push(` avg confidence: ${m.avgConfidence.toFixed(2)}`);
316
334
  lines.push(` chemistry delta: total=${m.totalChemistryDelta.toFixed(1)} max=${m.maxChemistryDelta.toFixed(1)}`);
317
335
  lines.push(` errors: ${m.errors.length}`);
@@ -387,8 +405,12 @@ export function toGitHubIssueBody(report) {
387
405
  lines.push("| Metric | Value |");
388
406
  lines.push("|--------|-------|");
389
407
  const rate = m.inputCount > 0 ? Math.round(m.classifiedCount / m.inputCount * 100) : 0;
408
+ const appraisalRate = m.inputCount > 0 ? Math.round(m.appraisalHitCount / m.inputCount * 100) : 0;
409
+ const semanticRate = m.inputCount > 0 ? Math.round(m.semanticHitCount / m.inputCount * 100) : 0;
390
410
  lines.push(`| Inputs | ${m.inputCount} |`);
391
411
  lines.push(`| Classified | ${m.classifiedCount} (${rate}%) |`);
412
+ lines.push(`| Appraisal Hits | ${m.appraisalHitCount} (${appraisalRate}%) |`);
413
+ lines.push(`| Recognized | ${m.semanticHitCount} (${semanticRate}%) |`);
392
414
  lines.push(`| Avg Confidence | ${m.avgConfidence.toFixed(2)} |`);
393
415
  lines.push(`| Chemistry Delta | total: ${m.totalChemistryDelta.toFixed(1)}, max: ${m.maxChemistryDelta.toFixed(1)} |`);
394
416
  lines.push(`| Errors | ${m.errors.length} |`);
@@ -418,6 +440,12 @@ export function formatLogEntry(report) {
418
440
  classifyRate: report.metrics.inputCount > 0
419
441
  ? +(report.metrics.classifiedCount / report.metrics.inputCount).toFixed(2)
420
442
  : 0,
443
+ appraisalRate: report.metrics.inputCount > 0
444
+ ? +(report.metrics.appraisalHitCount / report.metrics.inputCount).toFixed(2)
445
+ : 0,
446
+ recognitionRate: report.metrics.inputCount > 0
447
+ ? +(report.metrics.semanticHitCount / report.metrics.inputCount).toFixed(2)
448
+ : 0,
421
449
  errors: report.metrics.errors.length,
422
450
  chemDelta: +report.metrics.totalChemistryDelta.toFixed(1),
423
451
  });
@@ -452,6 +480,14 @@ export async function submitFeedback(report, url, timeout = 5000) {
452
480
  classifyRate: report.metrics.inputCount > 0
453
481
  ? +(report.metrics.classifiedCount / report.metrics.inputCount).toFixed(2)
454
482
  : 0,
483
+ appraisalHits: report.metrics.appraisalHitCount,
484
+ appraisalRate: report.metrics.inputCount > 0
485
+ ? +(report.metrics.appraisalHitCount / report.metrics.inputCount).toFixed(2)
486
+ : 0,
487
+ recognized: report.metrics.semanticHitCount,
488
+ recognitionRate: report.metrics.inputCount > 0
489
+ ? +(report.metrics.semanticHitCount / report.metrics.inputCount).toFixed(2)
490
+ : 0,
455
491
  chemDelta: +report.metrics.totalChemistryDelta.toFixed(1),
456
492
  maxChemDelta: +report.metrics.maxChemistryDelta.toFixed(1),
457
493
  errors: report.metrics.errors.length,
@@ -0,0 +1,5 @@
1
+ import type { GenerationControls, PolicyModifiers, ResponseContract } from "./types.js";
2
+ export declare function deriveGenerationControls(input: {
3
+ responseContract?: ResponseContract;
4
+ policyModifiers?: Pick<PolicyModifiers, "requireConfirmation">;
5
+ }, existingMaxTokens?: number): GenerationControls;
@@ -0,0 +1,48 @@
1
+ // ============================================================
2
+ // Host Controls — derive mechanical generation constraints
3
+ //
4
+ // Maps psyche output into a tiny host-consumable control surface.
5
+ // ============================================================
6
+ function clampInt(v, min, max) {
7
+ return Math.max(min, Math.min(max, Math.round(v)));
8
+ }
9
+ function estimateMaxTokens(contract) {
10
+ if (!contract)
11
+ return undefined;
12
+ let budget;
13
+ if (contract.maxChars !== undefined) {
14
+ budget = clampInt(contract.maxChars * 2.2, 64, 1024);
15
+ }
16
+ else if (contract.expressionMode === "brief") {
17
+ budget = 96;
18
+ }
19
+ else if (contract.expressionMode === "expansive") {
20
+ budget = 640;
21
+ }
22
+ else {
23
+ budget = 256;
24
+ }
25
+ if (contract.maxSentences <= 1)
26
+ budget = Math.min(budget, 96);
27
+ else if (contract.maxSentences === 2)
28
+ budget = Math.min(budget, 160);
29
+ else if (contract.maxSentences === 3)
30
+ budget = Math.min(budget, 320);
31
+ if (contract.initiativeMode === "reactive") {
32
+ budget = clampInt(budget * 0.85, 64, 1024);
33
+ }
34
+ return budget;
35
+ }
36
+ export function deriveGenerationControls(input, existingMaxTokens) {
37
+ const recommendedMax = estimateMaxTokens(input.responseContract);
38
+ const maxTokens = recommendedMax !== undefined
39
+ ? existingMaxTokens !== undefined
40
+ ? Math.min(existingMaxTokens, recommendedMax)
41
+ : recommendedMax
42
+ : existingMaxTokens;
43
+ return {
44
+ maxTokens,
45
+ requireConfirmation: input.policyModifiers?.requireConfirmation
46
+ ?? (input.responseContract?.boundaryMode === "confirm-first"),
47
+ };
48
+ }
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ export { PsycheEngine } from "./core.js";
2
2
  export type { PsycheEngineConfig, ProcessInputResult, ProcessOutputResult, ProcessOutcomeResult } from "./core.js";
3
3
  export { FileStorageAdapter, MemoryStorageAdapter } from "./storage.js";
4
4
  export type { StorageAdapter } from "./storage.js";
5
- export type { PsycheState, MBTIType, Locale, StimulusType, ChemicalState, ChemicalSnapshot, SelfModel, RelationshipState, EmpathyEntry, EmotionPattern, DriveType, InnateDrives, LearningState, LearnedVectorAdjustment, PredictionRecord, OutcomeScore, OutcomeSignals, AttachmentStyle, AttachmentData, MetacognitiveState, RegulationRecord, DefensePatternRecord, RegulationStrategyType, DefenseMechanismType, PersonhoodState, PersistedCausalInsight, GrowthDirection, PersonalityTraits, PsycheMode, PolicyModifiers, TraitDriftState, EnergyBudgets, ClassifierProvider, ClassifierContext, ClassificationResult, } from "./types.js";
6
- export { CHEMICAL_KEYS, CHEMICAL_NAMES, CHEMICAL_NAMES_ZH, DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ATTACHMENT, DRIVE_KEYS, DRIVE_NAMES_ZH, DEFAULT_TRAIT_DRIFT, DEFAULT_ENERGY_BUDGETS, } from "./types.js";
5
+ export type { PsycheState, MBTIType, Locale, StimulusType, ChemicalState, ChemicalSnapshot, SelfModel, RelationshipState, EmpathyEntry, EmotionPattern, DriveType, InnateDrives, LearningState, LearnedVectorAdjustment, PredictionRecord, OutcomeScore, OutcomeSignals, AttachmentStyle, AttachmentData, MetacognitiveState, RegulationRecord, DefensePatternRecord, RegulationStrategyType, DefenseMechanismType, PersonhoodState, PersistedCausalInsight, GrowthDirection, PersonalityTraits, PsycheMode, PolicyModifiers, SubjectivityKernel, ResponseContract, GenerationControls, AppraisalAxes, SubjectResidue, TaskPlaneState, SubjectPlaneState, RelationPlaneState, AmbiguityPlaneState, RelationMoveType, RelationMove, OpenLoopType, OpenLoopState, PendingRelationSignalState, DyadicFieldState, TraitDriftState, EnergyBudgets, ClassifierProvider, ClassifierContext, ClassificationResult, } from "./types.js";
6
+ export { CHEMICAL_KEYS, CHEMICAL_NAMES, CHEMICAL_NAMES_ZH, DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ATTACHMENT, DRIVE_KEYS, DRIVE_NAMES_ZH, DEFAULT_TRAIT_DRIFT, DEFAULT_ENERGY_BUDGETS, DEFAULT_APPRAISAL_AXES, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD, } from "./types.js";
7
7
  export { computeSelfReflection, computeEmotionalTendency, buildSelfReflectionContext } from "./self-recognition.js";
8
8
  export type { SelfReflection } from "./self-recognition.js";
9
9
  export { PsycheInteraction } from "./interaction.js";
@@ -23,6 +23,11 @@ export { assessMetacognition, computeEmotionalConfidence, generateRegulationSugg
23
23
  export type { MetacognitiveAssessment, RegulationSuggestion, DetectedDefense } from "./metacognition.js";
24
24
  export { computeDecisionBias, computeAttentionWeights, computeExploreExploit, buildDecisionContext, computePolicyModifiers, buildPolicyContext, } from "./decision-bias.js";
25
25
  export type { DecisionBiasVector, AttentionWeights } from "./decision-bias.js";
26
+ export { computeSubjectivityKernel, buildSubjectivityContext } from "./subjectivity.js";
27
+ export { computeResponseContract, buildResponseContractContext } from "./response-contract.js";
28
+ export { deriveGenerationControls } from "./host-controls.js";
29
+ export { computeAppraisalAxes, mergeAppraisalResidue, getResidueIntensity } from "./appraisal.js";
30
+ export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure } from "./relation-dynamics.js";
26
31
  export { computeExperientialField, computeCoherence, detectUnnamedEmotion, computeAffectCore } from "./experiential-field.js";
27
32
  export type { ExperientialField, ExperientialQuality, ConstructionContext } from "./experiential-field.js";
28
33
  export { computeGenerativeSelf, predictSelfReaction, detectInternalConflicts, buildIdentityNarrative } from "./generative-self.js";
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@
12
12
  export { PsycheEngine } from "./core.js";
13
13
  // Storage
14
14
  export { FileStorageAdapter, MemoryStorageAdapter } from "./storage.js";
15
- export { CHEMICAL_KEYS, CHEMICAL_NAMES, CHEMICAL_NAMES_ZH, DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ATTACHMENT, DRIVE_KEYS, DRIVE_NAMES_ZH, DEFAULT_TRAIT_DRIFT, DEFAULT_ENERGY_BUDGETS, } from "./types.js";
15
+ export { CHEMICAL_KEYS, CHEMICAL_NAMES, CHEMICAL_NAMES_ZH, DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ATTACHMENT, DRIVE_KEYS, DRIVE_NAMES_ZH, DEFAULT_TRAIT_DRIFT, DEFAULT_ENERGY_BUDGETS, DEFAULT_APPRAISAL_AXES, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD, } from "./types.js";
16
16
  // Self-recognition
17
17
  export { computeSelfReflection, computeEmotionalTendency, buildSelfReflectionContext } from "./self-recognition.js";
18
18
  // Multi-agent interaction
@@ -33,6 +33,12 @@ export { updateAttachment, computeSeparationEffect, computeReunionEffect, } from
33
33
  export { assessMetacognition, computeEmotionalConfidence, generateRegulationSuggestions, detectDefenseMechanisms, } from "./metacognition.js";
34
34
  // Decision bias (P5) + PolicyModifiers (v9)
35
35
  export { computeDecisionBias, computeAttentionWeights, computeExploreExploit, buildDecisionContext, computePolicyModifiers, buildPolicyContext, } from "./decision-bias.js";
36
+ // Subjectivity kernel (v9.3)
37
+ export { computeSubjectivityKernel, buildSubjectivityContext } from "./subjectivity.js";
38
+ export { computeResponseContract, buildResponseContractContext } from "./response-contract.js";
39
+ export { deriveGenerationControls } from "./host-controls.js";
40
+ export { computeAppraisalAxes, mergeAppraisalResidue, getResidueIntensity } from "./appraisal.js";
41
+ export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure } from "./relation-dynamics.js";
36
42
  // Experiential field (P6 + P8 Barrett construction)
37
43
  export { computeExperientialField, computeCoherence, detectUnnamedEmotion, computeAffectCore } from "./experiential-field.js";
38
44
  // Generative self (P6)
package/dist/prompt.d.ts CHANGED
@@ -15,6 +15,8 @@ export declare function buildDynamicContext(state: PsycheState, userId?: string,
15
15
  autonomicDescription?: string;
16
16
  autonomicState?: AutonomicState;
17
17
  primarySystemsDescription?: string;
18
+ subjectivityContext?: string;
19
+ responseContractContext?: string;
18
20
  policyContext?: string;
19
21
  }): string;
20
22
  /**
@@ -68,5 +70,7 @@ export declare function buildCompactContext(state: PsycheState, userId?: string,
68
70
  autonomicDescription?: string;
69
71
  autonomicState?: AutonomicState;
70
72
  primarySystemsDescription?: string;
73
+ subjectivityContext?: string;
74
+ responseContractContext?: string;
71
75
  policyContext?: string;
72
76
  }): string;