psyche-ai 9.2.6 → 9.2.7

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.
@@ -8,13 +8,31 @@
8
8
  //
9
9
  // Endpoints:
10
10
  // POST /process-input { text, userId? } → { systemContext, dynamicContext, stimulus, policyModifiers?, subjectivityKernel?, responseContract?, generationControls?, policyContext }
11
- // POST /process-output { text, userId? } → { cleanedText, stateChanged }
11
+ // POST /process-output { text, userId?, signals?, signalConfidence? } → { cleanedText, stateChanged }
12
12
  // GET /state → PsycheState
13
13
  // GET /protocol?locale=zh → { protocol }
14
14
  //
15
15
  // Zero dependencies — uses node:http only.
16
16
  // ============================================================
17
17
  import { createServer } from "node:http";
18
+ const VALID_WRITEBACK_SIGNALS = new Set([
19
+ "trust_up",
20
+ "trust_down",
21
+ "boundary_set",
22
+ "boundary_soften",
23
+ "repair_attempt",
24
+ "repair_landed",
25
+ "closeness_invite",
26
+ "withdrawal_mark",
27
+ "self_assertion",
28
+ "task_recenter",
29
+ ]);
30
+ function parseSignals(value) {
31
+ if (!Array.isArray(value))
32
+ return undefined;
33
+ const parsed = value.filter((item) => (typeof item === "string" && VALID_WRITEBACK_SIGNALS.has(item)));
34
+ return parsed.length > 0 ? [...new Set(parsed)] : undefined;
35
+ }
18
36
  // ── Server ───────────────────────────────────────────────────
19
37
  /**
20
38
  * Create an HTTP server that exposes PsycheEngine via REST API.
@@ -69,7 +87,11 @@ export function createPsycheServer(engine, opts) {
69
87
  // POST /process-output
70
88
  if (req.method === "POST" && url.pathname === "/process-output") {
71
89
  const body = await readBody(req);
72
- const result = await engine.processOutput(body.text ?? "", { userId: body.userId });
90
+ const result = await engine.processOutput(body.text ?? "", {
91
+ userId: body.userId,
92
+ signals: parseSignals(body.signals),
93
+ signalConfidence: typeof body.signalConfidence === "number" ? body.signalConfidence : undefined,
94
+ });
73
95
  json(res, 200, result);
74
96
  return;
75
97
  }
@@ -28,6 +28,8 @@ import type { PsycheEngine } from "../core.js";
28
28
  export declare class PsycheLangChain {
29
29
  private readonly engine;
30
30
  constructor(engine: PsycheEngine);
31
+ private readonly validSignals;
32
+ private parseSignals;
31
33
  /**
32
34
  * Get the system message to inject into the LLM call.
33
35
  * Combines the protocol (cacheable) and dynamic context (per-turn).
@@ -59,5 +61,7 @@ export declare class PsycheLangChain {
59
61
  */
60
62
  processResponse(text: string, opts?: {
61
63
  userId?: string;
64
+ signals?: string[];
65
+ signalConfidence?: number;
62
66
  }): Promise<string>;
63
67
  }
@@ -43,6 +43,24 @@ export class PsycheLangChain {
43
43
  constructor(engine) {
44
44
  this.engine = engine;
45
45
  }
46
+ validSignals = new Set([
47
+ "trust_up",
48
+ "trust_down",
49
+ "boundary_set",
50
+ "boundary_soften",
51
+ "repair_attempt",
52
+ "repair_landed",
53
+ "closeness_invite",
54
+ "withdrawal_mark",
55
+ "self_assertion",
56
+ "task_recenter",
57
+ ]);
58
+ parseSignals(signals) {
59
+ if (!signals)
60
+ return undefined;
61
+ const parsed = signals.filter((signal) => this.validSignals.has(signal));
62
+ return parsed.length > 0 ? [...new Set(parsed)] : undefined;
63
+ }
46
64
  /**
47
65
  * Get the system message to inject into the LLM call.
48
66
  * Combines the protocol (cacheable) and dynamic context (per-turn).
@@ -80,7 +98,11 @@ export class PsycheLangChain {
80
98
  * Call this AFTER the LLM invocation, before showing output to the user.
81
99
  */
82
100
  async processResponse(text, opts) {
83
- const result = await this.engine.processOutput(text, opts);
101
+ const result = await this.engine.processOutput(text, {
102
+ userId: opts?.userId,
103
+ signals: this.parseSignals(opts?.signals),
104
+ signalConfidence: opts?.signalConfidence,
105
+ });
84
106
  return result.cleanedText;
85
107
  }
86
108
  }
@@ -174,9 +174,11 @@ server.tool("process_output", "Process the LLM's response through the emotional
174
174
  "emotional contagion. Call this AFTER generating a response.", {
175
175
  text: z.string().describe("The LLM's response text"),
176
176
  userId: z.string().optional().describe("Optional user ID"),
177
- }, async ({ text, userId }) => {
177
+ signals: z.array(z.string()).optional().describe("Optional sparse writeback signals from the host"),
178
+ signalConfidence: z.number().min(0).max(1).optional().describe("Optional confidence for the supplied signals"),
179
+ }, async ({ text, userId, signals, signalConfidence }) => {
178
180
  const eng = await getEngine();
179
- const result = await eng.processOutput(text, { userId });
181
+ const result = await eng.processOutput(text, { userId, signals: signals, signalConfidence });
180
182
  return {
181
183
  content: [{
182
184
  type: "text",
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits, PolicyModifiers, ClassifierProvider, SubjectivityKernel, ResponseContract, GenerationControls } from "./types.js";
1
+ import type { PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits, PolicyModifiers, ClassifierProvider, SubjectivityKernel, ResponseContract, GenerationControls, SessionBridgeState, WritebackCalibrationFeedback, WritebackSignalType } from "./types.js";
2
2
  import type { StorageAdapter } from "./storage.js";
3
3
  import type { DiagnosticReport, SessionMetrics } from "./diagnostics.js";
4
4
  export interface PsycheEngineConfig {
@@ -36,6 +36,8 @@ export interface ProcessInputResult {
36
36
  dynamicContext: string;
37
37
  /** Detected stimulus type from user input, null if none */
38
38
  stimulus: StimulusType | null;
39
+ /** Confidence of the primary algorithmic stimulus guess, if any */
40
+ stimulusConfidence?: number;
39
41
  /** v9: Structured behavioral policy modifiers — machine-readable "off baseline" signals */
40
42
  policyModifiers?: PolicyModifiers;
41
43
  /** v9.3: Compact machine-readable subjective state for AI-first hosts */
@@ -44,6 +46,10 @@ export interface ProcessInputResult {
44
46
  responseContract?: ResponseContract;
45
47
  /** v9.3: Mechanical host controls derived from the reply envelope */
46
48
  generationControls?: GenerationControls;
49
+ /** v9.2.7: cold-start carry derived from persisted relation state */
50
+ sessionBridge?: SessionBridgeState | null;
51
+ /** v9.2.8: sparse writeback signals evaluated on the latest turn */
52
+ writebackFeedback?: WritebackCalibrationFeedback[];
47
53
  /**
48
54
  * v9: Ready-to-use LLM prompt fragment summarizing current behavioral policy.
49
55
  *
@@ -65,6 +71,11 @@ export interface ProcessOutputResult {
65
71
  /** Whether chemistry was meaningfully updated (contagion or psyche_update) */
66
72
  stateChanged: boolean;
67
73
  }
74
+ export interface ProcessOutputOptions {
75
+ userId?: string;
76
+ signals?: WritebackSignalType[];
77
+ signalConfidence?: number;
78
+ }
68
79
  export interface ProcessOutcomeResult {
69
80
  /** Outcome evaluation score (-1 to 1) */
70
81
  outcomeScore: OutcomeScore;
@@ -89,6 +100,8 @@ export declare class PsycheEngine {
89
100
  private lastReport;
90
101
  /** URL for auto-submitting diagnostic reports */
91
102
  private readonly feedbackUrl;
103
+ /** Most recent algorithmic stimulus read + confidence band */
104
+ private lastStimulusAssessment;
92
105
  constructor(config: PsycheEngineConfig | undefined, storage: StorageAdapter);
93
106
  /**
94
107
  * Load or create initial state. Must be called before processInput/processOutput.
@@ -105,9 +118,7 @@ export declare class PsycheEngine {
105
118
  * Phase 2: Process LLM output text.
106
119
  * Parses <psyche_update> tags, applies contagion, strips tags.
107
120
  */
108
- processOutput(text: string, opts?: {
109
- userId?: string;
110
- }): Promise<ProcessOutputResult>;
121
+ processOutput(text: string, opts?: ProcessOutputOptions): Promise<ProcessOutputResult>;
111
122
  /**
112
123
  * Phase 3 (optional): Explicitly evaluate the outcome of the last interaction.
113
124
  *
package/dist/core.js CHANGED
@@ -32,8 +32,18 @@ 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 { applyRelationalTurn } from "./relation-dynamics.js";
35
+ import { applyRelationalTurn, applySessionBridge, applyWritebackSignals, createWritebackCalibrations, evaluateWritebackCalibrations } from "./relation-dynamics.js";
36
36
  import { deriveReplyEnvelope } from "./reply-envelope.js";
37
+ function formatWritebackFeedbackNote(feedback, locale) {
38
+ const top = feedback?.[0];
39
+ if (!top)
40
+ return undefined;
41
+ if (locale === "zh") {
42
+ const effect = top.effect === "converging" ? "收敛" : top.effect === "diverging" ? "发散" : "持平";
43
+ return `写回:${top.signal} ${effect}。`;
44
+ }
45
+ return `Writeback: ${top.signal} ${top.effect}.`;
46
+ }
37
47
  const NOOP_LOGGER = { info: () => { }, warn: () => { }, debug: () => { } };
38
48
  const REPAIRING_STIMULI = new Set(["praise", "validation", "intimacy"]);
39
49
  const RELATIONSHIP_DELTAS = {
@@ -127,6 +137,8 @@ export class PsycheEngine {
127
137
  lastReport = null;
128
138
  /** URL for auto-submitting diagnostic reports */
129
139
  feedbackUrl;
140
+ /** Most recent algorithmic stimulus read + confidence band */
141
+ lastStimulusAssessment = null;
130
142
  constructor(config = {}, storage) {
131
143
  this.traits = config.traits;
132
144
  this.classifier = config.classifier ?? new BuiltInClassifier();
@@ -204,6 +216,12 @@ export class PsycheEngine {
204
216
  if (!loaded.pendingRelationSignals) {
205
217
  loaded.pendingRelationSignals = { _default: [] };
206
218
  }
219
+ if (!loaded.pendingWritebackCalibrations) {
220
+ loaded.pendingWritebackCalibrations = [];
221
+ }
222
+ if (!loaded.lastWritebackFeedback) {
223
+ loaded.lastWritebackFeedback = [];
224
+ }
207
225
  this.state = loaded;
208
226
  }
209
227
  else {
@@ -219,6 +237,8 @@ export class PsycheEngine {
219
237
  */
220
238
  async processInput(text, opts) {
221
239
  let state = this.ensureInitialized();
240
+ let sessionBridge = null;
241
+ let writebackFeedback = [];
222
242
  // ── Auto-learning: evaluate previous turn's outcome ──────
223
243
  if (this.pendingPrediction && text.length > 0) {
224
244
  const nextClassifications = classifyStimulus(text);
@@ -261,6 +281,9 @@ export class PsycheEngine {
261
281
  }
262
282
  // P12: Track session start for homeostatic pressure
263
283
  if (!state.sessionStartedAt) {
284
+ const bridged = applySessionBridge(state, { userId: opts?.userId, now: now.toISOString() });
285
+ state = bridged.state;
286
+ sessionBridge = bridged.bridge;
264
287
  state = { ...state, sessionStartedAt: now.toISOString() };
265
288
  }
266
289
  // Apply homeostatic pressure (fatigue from extended sessions)
@@ -311,6 +334,7 @@ export class PsycheEngine {
311
334
  }
312
335
  }
313
336
  const primary = classifications[0];
337
+ const primaryConfidence = primary?.confidence ?? 0;
314
338
  let current = state.current;
315
339
  if (primary && primary.confidence >= 0.5) {
316
340
  appliedStimulus = primary.type;
@@ -334,6 +358,18 @@ export class PsycheEngine {
334
358
  if (appliedStimulus) {
335
359
  state = applyRelationshipDrift(state, appliedStimulus, opts?.userId);
336
360
  }
361
+ this.lastStimulusAssessment = {
362
+ stimulus: primary?.type ?? null,
363
+ confidence: primaryConfidence,
364
+ overrideWindow: primaryConfidence >= 0.78 ? "narrow" : primaryConfidence >= 0.62 ? "balanced" : "wide",
365
+ };
366
+ }
367
+ else {
368
+ this.lastStimulusAssessment = {
369
+ stimulus: null,
370
+ confidence: 0,
371
+ overrideWindow: "wide",
372
+ };
337
373
  }
338
374
  // v9: Deplete energy budgets from this interaction turn
339
375
  energyBudgets = computeEnergyDepletion(energyBudgets, appliedStimulus, isExtravert);
@@ -361,6 +397,9 @@ export class PsycheEngine {
361
397
  },
362
398
  };
363
399
  }
400
+ const writebackEvaluation = evaluateWritebackCalibrations(state);
401
+ state = writebackEvaluation.state;
402
+ writebackFeedback = writebackEvaluation.feedback;
364
403
  // ── Locale (used by multiple subsystems below) ──────────
365
404
  const locale = state.meta.locale ?? this.cfg.locale;
366
405
  // ── P7+P10: Autonomic nervous system + Processing depth ────
@@ -517,7 +556,10 @@ export class PsycheEngine {
517
556
  this.diagnosticCollector.recordInput(appliedStimulus, appliedStimulus ? 1.0 : 0.0, state.current, appraisalAxes);
518
557
  }
519
558
  // Build metacognitive and decision context strings
520
- const metacogNote = metacognitiveAssessment?.metacognitiveNote;
559
+ const writebackNote = formatWritebackFeedbackNote(writebackFeedback, locale);
560
+ const metacogNote = writebackNote
561
+ ? [writebackNote, metacognitiveAssessment?.metacognitiveNote].filter(Boolean).join("\n")
562
+ : metacognitiveAssessment?.metacognitiveNote;
521
563
  const decisionCtx = buildDecisionContext(state);
522
564
  const ethicsCtx = ethicalAssessment ? buildEthicalContext(ethicalAssessment, locale) : undefined;
523
565
  const sharedCtx = sharedState ? buildSharedIntentionalityContext(sharedState, locale) : undefined;
@@ -527,6 +569,7 @@ export class PsycheEngine {
527
569
  locale,
528
570
  userText: text || undefined,
529
571
  algorithmStimulus: appliedStimulus,
572
+ classificationConfidence: this.lastStimulusAssessment?.confidence,
530
573
  personalityIntensity: this.cfg.personalityIntensity,
531
574
  relationContext: relationalTurn.relationContext,
532
575
  });
@@ -561,10 +604,13 @@ export class PsycheEngine {
561
604
  policyContext: replyEnvelope.policyContext || undefined,
562
605
  }),
563
606
  stimulus: appliedStimulus,
607
+ stimulusConfidence: this.lastStimulusAssessment?.confidence,
564
608
  policyModifiers: replyEnvelope.policyModifiers,
565
609
  subjectivityKernel: replyEnvelope.subjectivityKernel,
566
610
  responseContract: replyEnvelope.responseContract,
567
611
  generationControls: replyEnvelope.generationControls,
612
+ sessionBridge,
613
+ writebackFeedback,
568
614
  policyContext: replyEnvelope.policyContext,
569
615
  };
570
616
  }
@@ -582,10 +628,13 @@ export class PsycheEngine {
582
628
  policyContext: replyEnvelope.policyContext || undefined,
583
629
  }),
584
630
  stimulus: appliedStimulus,
631
+ stimulusConfidence: this.lastStimulusAssessment?.confidence,
585
632
  policyModifiers: replyEnvelope.policyModifiers,
586
633
  subjectivityKernel: replyEnvelope.subjectivityKernel,
587
634
  responseContract: replyEnvelope.responseContract,
588
635
  generationControls: replyEnvelope.generationControls,
636
+ sessionBridge,
637
+ writebackFeedback,
589
638
  policyContext: replyEnvelope.policyContext,
590
639
  };
591
640
  }
@@ -645,6 +694,8 @@ export class PsycheEngine {
645
694
  // Anti-sycophancy: track agreement streak
646
695
  state = updateAgreementStreak(state, text);
647
696
  // Parse and merge <psyche_update> from LLM output
697
+ let combinedSignals = [];
698
+ let combinedSignalConfidence = opts?.signalConfidence;
648
699
  if (text.includes("<psyche_update>")) {
649
700
  const parseResult = parsePsycheUpdate(text, NOOP_LOGGER);
650
701
  if (parseResult) {
@@ -652,7 +703,8 @@ export class PsycheEngine {
652
703
  stateChanged = true;
653
704
  // LLM-assisted classification: if algorithm didn't apply a stimulus
654
705
  // but LLM classified one, retroactively apply chemistry + drives
655
- if (parseResult.llmStimulus && !this._lastAlgorithmApplied) {
706
+ const overrideAllowed = this.lastStimulusAssessment?.overrideWindow !== "narrow";
707
+ if (parseResult.llmStimulus && (!this._lastAlgorithmApplied || overrideAllowed)) {
656
708
  state = {
657
709
  ...state,
658
710
  drives: feedDrives(state.drives, parseResult.llmStimulus),
@@ -660,11 +712,38 @@ export class PsycheEngine {
660
712
  const effectiveSensitivity = computeEffectiveSensitivity(getSensitivity(state.mbti), state.drives, parseResult.llmStimulus, state.traitDrift);
661
713
  state = {
662
714
  ...state,
663
- current: applyStimulus(state.current, parseResult.llmStimulus, effectiveSensitivity, this.cfg.maxChemicalDelta, NOOP_LOGGER),
715
+ current: applyStimulus(state.current, parseResult.llmStimulus, effectiveSensitivity * (overrideAllowed && this._lastAlgorithmApplied ? 0.8 : 1), this.cfg.maxChemicalDelta, NOOP_LOGGER),
664
716
  };
665
717
  }
718
+ if (parseResult.signals && parseResult.signals.length > 0) {
719
+ combinedSignals.push(...parseResult.signals);
720
+ combinedSignalConfidence = Math.max(combinedSignalConfidence ?? 0, parseResult.signalConfidence ?? 0);
721
+ }
666
722
  }
667
723
  }
724
+ if (opts?.signals && opts.signals.length > 0) {
725
+ combinedSignals.push(...opts.signals);
726
+ combinedSignalConfidence = Math.max(combinedSignalConfidence ?? 0, opts.signalConfidence ?? 0);
727
+ }
728
+ if (combinedSignals.length > 0) {
729
+ const dedupedSignals = [...new Set(combinedSignals)];
730
+ const pending = createWritebackCalibrations(state, dedupedSignals, {
731
+ userId: opts?.userId,
732
+ confidence: combinedSignalConfidence,
733
+ });
734
+ state = applyWritebackSignals(state, dedupedSignals, {
735
+ userId: opts?.userId,
736
+ confidence: combinedSignalConfidence,
737
+ });
738
+ state = {
739
+ ...state,
740
+ pendingWritebackCalibrations: [
741
+ ...(state.pendingWritebackCalibrations ?? []),
742
+ ...pending,
743
+ ].slice(-12),
744
+ };
745
+ stateChanged = true;
746
+ }
668
747
  // Persist
669
748
  this.state = state;
670
749
  await this.storage.save(state);
@@ -850,6 +929,8 @@ export class PsycheEngine {
850
929
  },
851
930
  },
852
931
  pendingRelationSignals: { _default: [] },
932
+ pendingWritebackCalibrations: [],
933
+ lastWritebackFeedback: [],
853
934
  meta: {
854
935
  agentName: name,
855
936
  createdAt: now,
@@ -889,6 +970,8 @@ export class PsycheEngine {
889
970
  },
890
971
  },
891
972
  pendingRelationSignals: { _default: [] },
973
+ pendingWritebackCalibrations: [],
974
+ lastWritebackFeedback: [],
892
975
  relationships: opts?.preserveRelationships !== false
893
976
  ? state.relationships
894
977
  : { _default: { ...DEFAULT_RELATIONSHIP } },
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ 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, SubjectivityKernel, ResponseContract, GenerationControls, AppraisalAxes, SubjectResidue, TaskPlaneState, SubjectPlaneState, RelationPlaneState, AmbiguityPlaneState, RelationMoveType, RelationMove, OpenLoopType, OpenLoopState, PendingRelationSignalState, DyadicFieldState, TraitDriftState, EnergyBudgets, ClassifierProvider, ClassifierContext, ClassificationResult, } 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, SessionBridgeState, WritebackSignalType, WritebackSignalWeightMap, PendingWritebackCalibration, WritebackCalibrationFeedback, WritebackCalibrationMetric, TraitDriftState, EnergyBudgets, ClassifierProvider, ClassifierContext, ClassificationResult, } from "./types.js";
6
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";
@@ -27,7 +27,7 @@ export { computeSubjectivityKernel, buildSubjectivityContext } from "./subjectiv
27
27
  export { computeResponseContract, buildResponseContractContext } from "./response-contract.js";
28
28
  export { deriveGenerationControls } from "./host-controls.js";
29
29
  export { computeAppraisalAxes, mergeAppraisalResidue, getResidueIntensity } from "./appraisal.js";
30
- export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure } from "./relation-dynamics.js";
30
+ export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure, applySessionBridge, applyWritebackSignals, createWritebackCalibrations, evaluateWritebackCalibrations, } from "./relation-dynamics.js";
31
31
  export { computeExperientialField, computeCoherence, detectUnnamedEmotion, computeAffectCore } from "./experiential-field.js";
32
32
  export type { ExperientialField, ExperientialQuality, ConstructionContext } from "./experiential-field.js";
33
33
  export { computeGenerativeSelf, predictSelfReaction, detectInternalConflicts, buildIdentityNarrative } from "./generative-self.js";
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ export { computeSubjectivityKernel, buildSubjectivityContext } from "./subjectiv
38
38
  export { computeResponseContract, buildResponseContractContext } from "./response-contract.js";
39
39
  export { deriveGenerationControls } from "./host-controls.js";
40
40
  export { computeAppraisalAxes, mergeAppraisalResidue, getResidueIntensity } from "./appraisal.js";
41
- export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure } from "./relation-dynamics.js";
41
+ export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure, applySessionBridge, applyWritebackSignals, createWritebackCalibrations, evaluateWritebackCalibrations, } from "./relation-dynamics.js";
42
42
  // Experiential field (P6 + P8 Barrett construction)
43
43
  export { computeExperientialField, computeCoherence, detectUnnamedEmotion, computeAffectCore } from "./experiential-field.js";
44
44
  // Generative self (P6)
package/dist/prompt.js CHANGED
@@ -468,8 +468,8 @@ function buildMirrorConstraints(userText, locale) {
468
468
  function buildCompactSensingContext(_userText, locale, algorithmStimulus) {
469
469
  if (locale === "zh") {
470
470
  return algorithmStimulus
471
- ? `[情绪感知] 算法初判:${algorithmStimulus},仅供参考;按真实感受终判语气。`
472
- : `[情绪感知] 这句的情绪基调由你终判。`;
471
+ ? `[情绪感知] 算法初判:${algorithmStimulus};你终判。`
472
+ : `[情绪感知] 情绪由你终判。`;
473
473
  }
474
474
  return algorithmStimulus
475
475
  ? `[Emotional Sensing] Algorithm hint: ${algorithmStimulus}; final tonal read is yours.`
@@ -1,4 +1,4 @@
1
- import type { PsycheState, MBTIType, ChemicalState, RelationshipState, Locale, StimulusType, ChemicalSnapshot } from "./types.js";
1
+ import type { PsycheState, MBTIType, ChemicalState, RelationshipState, Locale, StimulusType, ChemicalSnapshot, WritebackSignalType } from "./types.js";
2
2
  export interface SemanticTurnSummary {
3
3
  summary: string;
4
4
  points?: string[];
@@ -93,6 +93,10 @@ export interface PsycheUpdateResult {
93
93
  state: Partial<PsycheState>;
94
94
  /** LLM-assisted stimulus classification (when algorithm was uncertain) */
95
95
  llmStimulus?: StimulusType;
96
+ /** Sparse agent-authored writeback signals */
97
+ signals?: WritebackSignalType[];
98
+ /** Optional writeback confidence */
99
+ signalConfidence?: number;
96
100
  }
97
101
  /**
98
102
  * Parse a <psyche_update> block from LLM output.
@@ -710,10 +710,42 @@ export function parsePsycheUpdate(text, logger = NOOP_LOGGER) {
710
710
  llmStimulus = candidate;
711
711
  }
712
712
  }
713
+ const VALID_WRITEBACK_SIGNALS = new Set([
714
+ "trust_up",
715
+ "trust_down",
716
+ "boundary_set",
717
+ "boundary_soften",
718
+ "repair_attempt",
719
+ "repair_landed",
720
+ "closeness_invite",
721
+ "withdrawal_mark",
722
+ "self_assertion",
723
+ "task_recenter",
724
+ ]);
725
+ let signals;
726
+ const signalsMatch = block.match(/signals\s*[::]\s*([^\n]+)/i);
727
+ if (signalsMatch) {
728
+ const parsed = signalsMatch[1]
729
+ .split(/[,\s|]+/)
730
+ .map((item) => item.trim())
731
+ .filter(Boolean)
732
+ .filter((item) => VALID_WRITEBACK_SIGNALS.has(item));
733
+ if (parsed.length > 0) {
734
+ signals = [...new Set(parsed)];
735
+ }
736
+ }
737
+ let signalConfidence;
738
+ const signalConfidenceMatch = block.match(/(?:signalConfidence|signalsConfidence|signal_confidence)\s*[::]\s*([\d.]+)/i);
739
+ if (signalConfidenceMatch) {
740
+ const parsed = parseFloat(signalConfidenceMatch[1]);
741
+ if (isFinite(parsed)) {
742
+ signalConfidence = Math.max(0, Math.min(1, parsed));
743
+ }
744
+ }
713
745
  // Parse relationship updates
714
746
  const trustMatch = block.match(/(?:信任度|trust)\s*[::]\s*(\d+)/i);
715
747
  const intimacyMatch = block.match(/(?:亲密度|intimacy)\s*[::]\s*(\d+)/i);
716
- if (Object.keys(updates).length === 0 && !empathyLog && !trustMatch && !llmStimulus) {
748
+ if (Object.keys(updates).length === 0 && !empathyLog && !trustMatch && !llmStimulus && !signals) {
717
749
  logger.debug(t("log.parse_debug", "zh", { snippet: block.slice(0, 100) }));
718
750
  return null;
719
751
  }
@@ -738,6 +770,12 @@ export function parsePsycheUpdate(text, logger = NOOP_LOGGER) {
738
770
  if (llmStimulus) {
739
771
  result.llmStimulus = llmStimulus;
740
772
  }
773
+ if (signals) {
774
+ result.signals = signals;
775
+ }
776
+ if (signalConfidence !== undefined) {
777
+ result.signalConfidence = signalConfidence;
778
+ }
741
779
  return result;
742
780
  }
743
781
  /**
@@ -1,4 +1,4 @@
1
- import type { PendingRelationSignalState, AppraisalAxes, DyadicFieldState, PsycheState, RelationshipState, ResolvedRelationContext, PsycheMode, RelationMove, StimulusType } from "./types.js";
1
+ import type { PendingRelationSignalState, AppraisalAxes, DyadicFieldState, PendingWritebackCalibration, PsycheState, RelationshipState, ResolvedRelationContext, PsycheMode, RelationMove, SessionBridgeState, StimulusType, WritebackCalibrationFeedback, WritebackSignalType } from "./types.js";
2
2
  export declare function computeRelationMove(text: string, opts?: {
3
3
  appraisal?: AppraisalAxes;
4
4
  stimulus?: StimulusType | null;
@@ -7,6 +7,27 @@ export declare function computeRelationMove(text: string, opts?: {
7
7
  relationship?: RelationshipState;
8
8
  }): RelationMove;
9
9
  export declare function resolveRelationContext(state: PsycheState, userId?: string): ResolvedRelationContext;
10
+ export declare function applySessionBridge(state: PsycheState, opts?: {
11
+ userId?: string;
12
+ now?: string;
13
+ }): {
14
+ state: PsycheState;
15
+ bridge: SessionBridgeState | null;
16
+ };
17
+ export declare function createWritebackCalibrations(state: PsycheState, signals: WritebackSignalType[], opts?: {
18
+ userId?: string;
19
+ confidence?: number;
20
+ now?: string;
21
+ }): PendingWritebackCalibration[];
22
+ export declare function evaluateWritebackCalibrations(state: PsycheState): {
23
+ state: PsycheState;
24
+ feedback: WritebackCalibrationFeedback[];
25
+ };
26
+ export declare function applyWritebackSignals(state: PsycheState, signals: WritebackSignalType[], opts?: {
27
+ userId?: string;
28
+ confidence?: number;
29
+ now?: string;
30
+ }): PsycheState;
10
31
  export declare function applyRelationalTurn(state: PsycheState, text: string, opts: {
11
32
  mode?: PsycheMode;
12
33
  now?: string;