psyche-ai 9.2.9 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,71 +1,186 @@
1
1
  // ============================================================
2
2
  // psyche-ai — Universal AI Emotional Intelligence Plugin
3
3
  //
4
- // Main entry point: re-exports core, storage, types.
4
+ // Public API surface (~20 essential exports).
5
+ // Internal computation functions remain accessible via direct
6
+ // module imports (e.g. "psyche-ai/src/learning.js") for tests
7
+ // and advanced use, but are NOT part of the public contract.
8
+ //
5
9
  // Framework adapters available via subpath imports:
6
10
  // psyche-ai/openclaw — OpenClaw plugin
7
11
  // psyche-ai/vercel-ai — Vercel AI SDK middleware
8
12
  // psyche-ai/langchain — LangChain helper
9
13
  // psyche-ai/http — HTTP server for Python/Go/etc.
10
14
  // ============================================================
11
- // Core
15
+ // ── Core engine ─────────────────────────────────────────────
12
16
  export { PsycheEngine } from "./core.js";
13
- // Storage
17
+ // ── Storage ─────────────────────────────────────────────────
14
18
  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, DEFAULT_APPRAISAL_AXES, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD, } from "./types.js";
16
- // Self-recognition
17
- export { computeSelfReflection, computeEmotionalTendency, buildSelfReflectionContext } from "./self-recognition.js";
18
- // Multi-agent interaction
19
- export { PsycheInteraction } from "./interaction.js";
20
- // Channels
21
- export { getChannelProfile, buildChannelModifier, createCustomChannel } from "./channels.js";
22
- // Custom profiles beyond MBTI presets
23
- export { createCustomProfile, validateProfileConfig, PRESET_PROFILES } from "./custom-profile.js";
24
- // Emotional learning (P3)
25
- export { evaluateOutcome, getLearnedVector, updateLearnedVector, computeContextHash, predictChemistry, computePredictionError, recordPrediction, getAveragePredictionError, } from "./learning.js";
26
- // Context-aware classification (P3)
27
- export { classifyStimulusWithContext, extractContextFeatures, stimulusWarmth } from "./context-classifier.js";
28
- // Temporal consciousness (P4)
29
- export { predictNextStimulus, generateAnticipation, computeSurpriseEffect, computeRegret, } from "./temporal.js";
30
- // Attachment dynamics (P4)
31
- export { updateAttachment, computeSeparationEffect, computeReunionEffect, } from "./attachment.js";
32
- // Metacognition (P5)
33
- export { assessMetacognition, computeEmotionalConfidence, generateRegulationSuggestions, detectDefenseMechanisms, } from "./metacognition.js";
34
- // Decision bias (P5) + PolicyModifiers (v9)
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 { deriveReplyEnvelope } from "./reply-envelope.js";
41
- export { computeAppraisalAxes, mergeAppraisalResidue, getResidueIntensity } from "./appraisal.js";
42
- export { computeRelationMove, evolveDyadicField, evolvePendingRelationSignals, getLoopPressure, applySessionBridge, applyWritebackSignals, createWritebackCalibrations, evaluateWritebackCalibrations, } from "./relation-dynamics.js";
43
- export { EXTERNAL_CONTINUITY_SIGNAL_KINDS, EXTERNAL_CONTINUITY_TRACE_KINDS, buildExternalContinuityEnvelope, } from "./external-continuity.js";
44
- export { deriveThrongletsExports } from "./thronglets-export.js";
45
- export { taxonomyForThrongletsExport, serializeThrongletsExportAsTrace, serializeExternalContinuityForThronglets, } from "./thronglets-runtime.js";
46
- export { runRuntimeProbe } from "./runtime-probe.js";
47
- // Experiential field (P6 + P8 Barrett construction)
48
- export { computeExperientialField, computeCoherence, detectUnnamedEmotion, computeAffectCore } from "./experiential-field.js";
49
- // Generative self (P6)
50
- export { computeGenerativeSelf, predictSelfReaction, detectInternalConflicts, buildIdentityNarrative } from "./generative-self.js";
51
- // Shared intentionality (P6)
52
- export { updateSharedIntentionality, estimateOtherMood, buildSharedIntentionalityContext } from "./shared-intentionality.js";
53
- // Emotional ethics (P6)
54
- export { assessEthics, detectIntermittentReinforcement, detectDependencyRisk, buildEthicalContext, } from "./ethics.js";
55
- // Autonomic nervous system (P7)
56
- export { computeAutonomicResult, computeAutonomicState, computeProcessingDepth, gateEmotions, getTransitionTime, describeAutonomicState } from "./autonomic.js";
57
- // Circadian rhythms (P12)
58
- export { computeCircadianModulation, computeHomeostaticPressure, getCircadianPhase, computeEnergyDepletion, computeEnergyRecovery } from "./circadian.js";
59
- // Primary emotional systems — Panksepp (P9)
60
- export { computePrimarySystems, computeSystemInteractions, gatePrimarySystemsByAutonomic, getDominantSystems, describeBehavioralTendencies, PRIMARY_SYSTEM_NAMES, } from "./primary-systems.js";
61
- // Utilities — for custom adapter / advanced use
62
- // Trait drift (v9)
63
- export { updateTraitDrift } from "./drives.js";
64
- // Utilities — for custom adapter / advanced use
65
- export { classifyStimulus, getPrimaryStimulus, scoreSentiment, scoreEmoji, BuiltInClassifier, analyzeParticles, detectIntent, buildLLMClassifierPrompt, parseLLMClassification } from "./classify.js";
66
- export { buildProtocolContext, buildDynamicContext, buildCompactContext, isNearBaseline, getNearBaselineThreshold } from "./prompt.js";
67
- export { describeEmotionalState, getExpressionHint, getBehaviorGuide, detectEmotions } from "./chemistry.js";
68
- export { getBaseline, getTemperament, getSensitivity, getDefaultSelfModel, traitsToBaseline, mbtiToTraits } from "./profiles.js";
69
- export { migrateToLatest, compressSession, parsePsycheUpdate, computeSnapshotIntensity, computeSnapshotValence, consolidateHistory, retrieveRelatedMemories, } from "./psyche-file.js";
70
- // ── Diagnostics ──────────────────────────────────────────────
71
- export { runHealthCheck, DiagnosticCollector, generateReport, formatReport, toGitHubIssueBody, formatLogEntry, submitFeedback, } from "./diagnostics.js";
19
+ // ── Prompt context builders ─────────────────────────────────
20
+ export { buildProtocolContext, buildCompactContext } from "./prompt.js";
21
+ /** @deprecated Use buildCompactContext instead. Kept for backward compat. */
22
+ export { buildDynamicContext } from "./prompt.js";
23
+ export { isNearBaseline, getNearBaselineThreshold, deriveBehavioralBias, computeUserInvestment } from "./prompt.js";
24
+ // ── Profile helpers ─────────────────────────────────────────
25
+ export { getBaseline, getSensitivity, getDefaultSelfModel, getTemperament, traitsToBaseline, mbtiToTraits } from "./profiles.js";
26
+ export { createCustomProfile, PRESET_PROFILES } from "./custom-profile.js";
27
+ // ── Diagnostics ─────────────────────────────────────────────
28
+ export { computeLayerHealthSummary } from "./diagnostics.js";
29
+ // ============================================================
30
+ // INTENTIONALLY REMOVED FROM PUBLIC API (v9.3)
31
+ //
32
+ // The following were previously exported but are internal
33
+ // implementation details. They remain importable via direct
34
+ // module paths for tests and advanced integrations:
35
+ //
36
+ // types.js (constants & defaults):
37
+ // CHEMICAL_KEYS, CHEMICAL_NAMES, CHEMICAL_NAMES_ZH, DRIVE_KEYS,
38
+ // DRIVE_NAMES_ZH, DEFAULT_RELATIONSHIP, DEFAULT_DRIVES,
39
+ // DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE,
40
+ // DEFAULT_PERSONHOOD_STATE, DEFAULT_ATTACHMENT,
41
+ // DEFAULT_TRAIT_DRIFT, DEFAULT_ENERGY_BUDGETS,
42
+ // DEFAULT_APPRAISAL_AXES, DEFAULT_SUBJECT_RESIDUE,
43
+ // DEFAULT_DYADIC_FIELD
44
+ //
45
+ // types.js (internal type aliases):
46
+ // ChemicalSnapshot, SelfModel, RelationshipState, EmpathyEntry,
47
+ // EmotionPattern, DriveType, InnateDrives, LearningState,
48
+ // LearnedVectorAdjustment, PredictionRecord, OutcomeScore,
49
+ // OutcomeSignals, AttachmentStyle, AttachmentData,
50
+ // MetacognitiveState, RegulationRecord, DefensePatternRecord,
51
+ // RegulationStrategyType, DefenseMechanismType, PersonhoodState,
52
+ // PersistedCausalInsight, GrowthDirection, PersonalityTraits,
53
+ // PolicyModifiers, SubjectivityKernel, ResponseContract,
54
+ // GenerationControls, TurnControlPlane, TurnControlDriver,
55
+ // ControlBoundaryObservation, StateLayerKind,
56
+ // StateLayerObservation, PromptRenderInputName, RuntimeHookName,
57
+ // OutputAttributionObservation, StateReconciliationObservation,
58
+ // DecisionEvidenceObservation, DecisionCandidateName,
59
+ // DecisionCandidateObservation, DecisionRationaleObservation,
60
+ // CausalChainObservation, ExternalTraceMappingObservation,
61
+ // TurnObservability, AppraisalAxes, SubjectResidue,
62
+ // TaskPlaneState, SubjectPlaneState, RelationPlaneState,
63
+ // AmbiguityPlaneState, RelationMoveType, RelationMove,
64
+ // OpenLoopType, OpenLoopState, PendingRelationSignalState,
65
+ // DyadicFieldState, SessionBridgeState,
66
+ // ThrongletsExport* types, ExternalContinuity* types,
67
+ // WritebackSignalWeightMap, PendingWritebackCalibration,
68
+ // WritebackCalibrationFeedback, WritebackCalibrationMetric,
69
+ // TraitDriftState, EnergyBudgets, ClassifierProvider,
70
+ // ClassifierContext, ClassificationResult
71
+ //
72
+ // self-recognition.js:
73
+ // computeSelfReflection, computeEmotionalTendency,
74
+ // buildSelfReflectionContext, SelfReflection
75
+ //
76
+ // interaction.js:
77
+ // PsycheInteraction, ExchangeResult, ContagionResult,
78
+ // RelationshipSummary, InteractionPhase
79
+ //
80
+ // channels.js:
81
+ // getChannelProfile, buildChannelModifier, createCustomChannel,
82
+ // ChannelType, ChannelProfile
83
+ //
84
+ // custom-profile.js:
85
+ // validateProfileConfig, CustomProfileConfig, ResolvedProfile
86
+ //
87
+ // learning.js:
88
+ // evaluateOutcome, getLearnedVector, updateLearnedVector,
89
+ // computeContextHash, predictChemistry, computePredictionError,
90
+ // recordPrediction, getAveragePredictionError
91
+ //
92
+ // context-classifier.js:
93
+ // classifyStimulusWithContext, extractContextFeatures,
94
+ // stimulusWarmth, ContextFeatures, ContextualClassification
95
+ //
96
+ // temporal.js:
97
+ // predictNextStimulus, generateAnticipation,
98
+ // computeSurpriseEffect, computeRegret, StimulusPrediction,
99
+ // AnticipationState, RegretEntry
100
+ //
101
+ // attachment.js:
102
+ // updateAttachment, computeSeparationEffect,
103
+ // computeReunionEffect, SeparationEffect
104
+ //
105
+ // metacognition.js:
106
+ // assessMetacognition, computeEmotionalConfidence,
107
+ // generateRegulationSuggestions, detectDefenseMechanisms,
108
+ // MetacognitiveAssessment, RegulationSuggestion, DetectedDefense
109
+ //
110
+ // decision-bias.js:
111
+ // computeDecisionBias, computeAttentionWeights,
112
+ // computeExploreExploit, buildDecisionContext,
113
+ // computePolicyModifiers, buildPolicyContext,
114
+ // DecisionBiasVector, AttentionWeights
115
+ //
116
+ // subjectivity.js, response-contract.js, host-controls.js,
117
+ // reply-envelope.js, observability.js, appraisal.js,
118
+ // relation-dynamics.js, external-continuity.js,
119
+ // thronglets-export.js, thronglets-runtime.js,
120
+ // runtime-probe.js:
121
+ // All functions & types (orchestrated by PsycheEngine)
122
+ //
123
+ // experiential-field.js:
124
+ // computeExperientialField, computeCoherence,
125
+ // detectUnnamedEmotion, computeAffectCore, ExperientialField,
126
+ // ExperientialQuality, ConstructionContext
127
+ //
128
+ // generative-self.js:
129
+ // computeGenerativeSelf, predictSelfReaction,
130
+ // detectInternalConflicts, buildIdentityNarrative,
131
+ // GenerativeSelfModel, CausalInsight, SelfPrediction,
132
+ // GrowthArc, InternalConflict
133
+ //
134
+ // shared-intentionality.js:
135
+ // updateSharedIntentionality, estimateOtherMood,
136
+ // buildSharedIntentionalityContext, SharedIntentionalityState,
137
+ // TheoryOfMindModel, JointAttentionTopic, GoalAlignment
138
+ //
139
+ // ethics.js:
140
+ // assessEthics, detectIntermittentReinforcement,
141
+ // detectDependencyRisk, buildEthicalContext,
142
+ // EthicalAssessment, EthicalConcern, SelfProtectionAction
143
+ //
144
+ // autonomic.js:
145
+ // computeAutonomicResult, computeAutonomicState,
146
+ // computeProcessingDepth, gateEmotions, getTransitionTime,
147
+ // describeAutonomicState, AutonomicState, AutonomicResult,
148
+ // AutonomicTransition
149
+ //
150
+ // circadian.js:
151
+ // computeCircadianModulation, computeHomeostaticPressure,
152
+ // getCircadianPhase, computeEnergyDepletion,
153
+ // computeEnergyRecovery, CircadianPhase
154
+ //
155
+ // primary-systems.js:
156
+ // computePrimarySystems, computeSystemInteractions,
157
+ // gatePrimarySystemsByAutonomic, getDominantSystems,
158
+ // describeBehavioralTendencies, PRIMARY_SYSTEM_NAMES,
159
+ // PrimarySystemName, PrimarySystemLevels,
160
+ // BehavioralTendency, DominantSystem
161
+ //
162
+ // classify.js:
163
+ // classifyStimulus, getPrimaryStimulus, scoreSentiment,
164
+ // scoreEmoji, BuiltInClassifier, analyzeParticles, detectIntent,
165
+ // buildLLMClassifierPrompt, parseLLMClassification,
166
+ // StimulusClassification, ParticleSignal, MessageIntent
167
+ //
168
+ // chemistry.js:
169
+ // describeEmotionalState, getExpressionHint,
170
+ // getBehaviorGuide, detectEmotions
171
+ //
172
+ // drives.js:
173
+ // updateTraitDrift
174
+ //
175
+ // psyche-file.js:
176
+ // migrateToLatest, compressSession, parsePsycheUpdate,
177
+ // computeSnapshotIntensity, computeSnapshotValence,
178
+ // consolidateHistory, retrieveRelatedMemories,
179
+ // PsycheUpdateResult
180
+ //
181
+ // diagnostics.js (remaining):
182
+ // runHealthCheck, DiagnosticCollector, generateReport,
183
+ // formatReport, toGitHubIssueBody, formatLogEntry,
184
+ // submitFeedback, DiagnosticIssue, DiagnosticReport,
185
+ // SessionMetrics, Severity
186
+ // ============================================================
@@ -0,0 +1,14 @@
1
+ import type { PsycheState, ResolvedRelationContext, SessionBridgeState, StimulusType, ThrongletsExport, TurnObservability, WritebackCalibrationFeedback } from "./types.js";
2
+ import type { PromptRenderInputs } from "./prompt.js";
3
+ import type { ReplyEnvelope } from "./reply-envelope.js";
4
+ export declare function buildTurnObservability(state: PsycheState, opts: {
5
+ replyEnvelope: ReplyEnvelope;
6
+ promptRenderInputs: PromptRenderInputs;
7
+ compactMode: boolean;
8
+ stimulus: StimulusType | null;
9
+ userText?: string;
10
+ sessionBridge: SessionBridgeState | null;
11
+ writebackFeedback: WritebackCalibrationFeedback[];
12
+ relationContext?: ResolvedRelationContext;
13
+ externalContinuityEvents: ThrongletsExport[];
14
+ }): TurnObservability;
@@ -0,0 +1,392 @@
1
+ function clamp01(v) {
2
+ return Math.max(0, Math.min(1, v));
3
+ }
4
+ function pickDominantPlane(replyEnvelope) {
5
+ const { subjectivityKernel, responseContract } = replyEnvelope;
6
+ const taskCandidates = [
7
+ ["task-focus", subjectivityKernel.taskPlane.focus],
8
+ ["discipline", subjectivityKernel.taskPlane.discipline],
9
+ ];
10
+ const subjectCandidates = [
11
+ ["attachment", subjectivityKernel.subjectPlane.attachment],
12
+ ["guardedness", subjectivityKernel.subjectPlane.guardedness],
13
+ ["identity-strain", subjectivityKernel.subjectPlane.identityStrain],
14
+ ["residue", subjectivityKernel.subjectPlane.residue],
15
+ ];
16
+ const relationCandidates = [
17
+ ["closeness", subjectivityKernel.relationPlane.closeness],
18
+ ["loop-pressure", subjectivityKernel.relationPlane.loopPressure],
19
+ ["repair-readiness", subjectivityKernel.relationPlane.repairReadiness],
20
+ ["repair-friction", subjectivityKernel.relationPlane.repairFriction],
21
+ ["hysteresis", subjectivityKernel.relationPlane.hysteresis],
22
+ ["silent-carry", subjectivityKernel.relationPlane.silentCarry],
23
+ ];
24
+ const ambiguityCandidates = [
25
+ ["conflict-load", subjectivityKernel.ambiguityPlane.conflictLoad],
26
+ ["expression-inhibition", subjectivityKernel.ambiguityPlane.expressionInhibition],
27
+ ["naming-uncertainty", 1 - subjectivityKernel.ambiguityPlane.namingConfidence],
28
+ ];
29
+ const planeSummaries = [
30
+ ["task", ...taskCandidates.sort((a, b) => b[1] - a[1])[0]],
31
+ ["subject", ...subjectCandidates.sort((a, b) => b[1] - a[1])[0]],
32
+ ["relation", ...relationCandidates.sort((a, b) => b[1] - a[1])[0]],
33
+ ["ambiguity", ...ambiguityCandidates.sort((a, b) => b[1] - a[1])[0]],
34
+ ];
35
+ planeSummaries.sort((a, b) => {
36
+ if (b[2] !== a[2])
37
+ return b[2] - a[2];
38
+ if (responseContract.replyProfile === "work") {
39
+ if (a[0] === "task")
40
+ return -1;
41
+ if (b[0] === "task")
42
+ return 1;
43
+ }
44
+ return 0;
45
+ });
46
+ const [dominantPlane, dominantDriver, strength] = planeSummaries[0];
47
+ return {
48
+ dominantPlane,
49
+ dominantDriver,
50
+ strength: clamp01(strength),
51
+ replyProfile: responseContract.replyProfile,
52
+ replyProfileBasis: responseContract.replyProfileBasis,
53
+ overrideWindow: responseContract.overrideWindow,
54
+ };
55
+ }
56
+ function summarizeCurrentTurn(stimulus, userText) {
57
+ if (stimulus)
58
+ return `stimulus:${stimulus}`;
59
+ if (userText && userText.trim().length > 0)
60
+ return "stimulus:none";
61
+ return "no-user-input";
62
+ }
63
+ function summarizeWriteback(feedback) {
64
+ if (feedback.length === 0)
65
+ return "none";
66
+ const top = feedback[0];
67
+ return `${top.signal}:${top.effect}`;
68
+ }
69
+ function summarizeSessionBridge(bridge) {
70
+ if (!bridge)
71
+ return "none";
72
+ const loops = bridge.activeLoopTypes.length > 0 ? bridge.activeLoopTypes.join("+") : "no-open-loops";
73
+ return `${bridge.continuityMode}/${loops}`;
74
+ }
75
+ function summarizeRelationship(state, relationContext) {
76
+ const relationship = relationContext?.relationship
77
+ ?? state.relationships._default
78
+ ?? state.relationships[Object.keys(state.relationships)[0]];
79
+ if (!relationship)
80
+ return "none";
81
+ return `${relationship.phase}/trust:${Math.round(relationship.trust)}/intimacy:${Math.round(relationship.intimacy)}`;
82
+ }
83
+ function buildStateLayers(state, opts) {
84
+ return [
85
+ {
86
+ layer: "current-turn",
87
+ precedence: 1,
88
+ scope: "turn",
89
+ active: Boolean(opts.stimulus) || Boolean(opts.userText?.trim()),
90
+ summary: summarizeCurrentTurn(opts.stimulus, opts.userText),
91
+ },
92
+ {
93
+ layer: "writeback-feedback",
94
+ precedence: 2,
95
+ scope: "session",
96
+ active: opts.writebackFeedback.length > 0,
97
+ summary: summarizeWriteback(opts.writebackFeedback),
98
+ },
99
+ {
100
+ layer: "session-bridge",
101
+ precedence: 3,
102
+ scope: "session",
103
+ active: Boolean(opts.sessionBridge),
104
+ summary: summarizeSessionBridge(opts.sessionBridge),
105
+ },
106
+ {
107
+ layer: "persisted-relationship",
108
+ precedence: 4,
109
+ scope: "persistent",
110
+ active: true,
111
+ summary: summarizeRelationship(state, opts.relationContext),
112
+ },
113
+ ];
114
+ }
115
+ function buildStateReconciliation(stateLayers) {
116
+ const activeObservations = stateLayers
117
+ .filter((layer) => layer.active)
118
+ .sort((a, b) => a.precedence - b.precedence);
119
+ const activeLayers = activeObservations.map((layer) => layer.layer);
120
+ const carryLayers = activeLayers.filter((layer) => layer !== "current-turn");
121
+ const governingLayer = activeObservations[0]?.layer ?? "persisted-relationship";
122
+ let resolution = "persistent-baseline";
123
+ if (activeLayers.includes("writeback-feedback")) {
124
+ resolution = "writeback-adjusted";
125
+ }
126
+ else if (activeLayers.includes("session-bridge") && activeLayers.includes("current-turn")) {
127
+ resolution = "session-bridge-biased";
128
+ }
129
+ else if (activeLayers.includes("current-turn")) {
130
+ resolution = "current-turn-dominant";
131
+ }
132
+ const notes = stateLayers
133
+ .filter((layer) => layer.active && layer.layer !== "persisted-relationship")
134
+ .map((layer) => `${layer.layer}:${layer.summary}`);
135
+ return {
136
+ governingLayer,
137
+ activeLayers,
138
+ carryLayers,
139
+ resolution,
140
+ notes,
141
+ };
142
+ }
143
+ function pushReason(reasons, condition, label) {
144
+ if (condition)
145
+ reasons.push(label);
146
+ }
147
+ function pushEvidence(evidence, opts) {
148
+ if (!opts.condition)
149
+ return;
150
+ evidence.push({
151
+ ruleId: opts.ruleId,
152
+ sourceMetric: opts.sourceMetric,
153
+ rawValue: opts.rawValue,
154
+ threshold: opts.threshold,
155
+ contribution: clamp01(opts.contribution),
156
+ });
157
+ }
158
+ function buildDecisionRationale(replyEnvelope) {
159
+ const { subjectivityKernel, responseContract } = replyEnvelope;
160
+ const taskFocus = subjectivityKernel.taskPlane.focus;
161
+ const discipline = subjectivityKernel.taskPlane.discipline;
162
+ const attachment = subjectivityKernel.subjectPlane.attachment;
163
+ const residue = subjectivityKernel.subjectPlane.residue;
164
+ const guardedness = subjectivityKernel.subjectPlane.guardedness;
165
+ const closeness = subjectivityKernel.relationPlane.closeness;
166
+ const loopPressure = subjectivityKernel.relationPlane.loopPressure;
167
+ const repairFriction = subjectivityKernel.relationPlane.repairFriction;
168
+ const expressionInhibition = subjectivityKernel.ambiguityPlane.expressionInhibition;
169
+ const namingConfidence = subjectivityKernel.ambiguityPlane.namingConfidence;
170
+ const taskFocused = taskFocus >= 0.62;
171
+ const disciplined = discipline >= 0.72;
172
+ const triggerConditions = [];
173
+ pushReason(triggerConditions, taskFocused, "task-focus>=0.62");
174
+ pushReason(triggerConditions, disciplined, "discipline>=0.72");
175
+ pushReason(triggerConditions, expressionInhibition > 0.64, "expression-inhibition>0.64");
176
+ pushReason(triggerConditions, loopPressure > 0.68, "loop-pressure>0.68");
177
+ pushReason(triggerConditions, repairFriction > 0.6, "repair-friction>0.60");
178
+ pushReason(triggerConditions, namingConfidence < 0.36, "naming-confidence<0.36");
179
+ if (triggerConditions.length === 0) {
180
+ triggerConditions.push("default-private-fallback");
181
+ }
182
+ const workReasons = [];
183
+ const workEvidence = [];
184
+ pushReason(workReasons, taskFocused, "task focus crossed work threshold");
185
+ pushReason(workReasons, disciplined, "discipline crossed work threshold");
186
+ pushReason(workReasons, taskFocus > 0.78 && discipline > 0.68, "high task-focus and discipline reinforce work mode");
187
+ pushEvidence(workEvidence, {
188
+ ruleId: "reply-profile.work.task-focus-threshold",
189
+ sourceMetric: "taskPlane.focus",
190
+ rawValue: taskFocus,
191
+ threshold: 0.62,
192
+ contribution: 0.55,
193
+ condition: taskFocused,
194
+ });
195
+ pushEvidence(workEvidence, {
196
+ ruleId: "reply-profile.work.discipline-threshold",
197
+ sourceMetric: "taskPlane.discipline",
198
+ rawValue: discipline,
199
+ threshold: 0.72,
200
+ contribution: 0.45,
201
+ condition: disciplined,
202
+ });
203
+ const workScore = clamp01(workEvidence.reduce((sum, item) => sum + item.contribution, 0));
204
+ const privateReasons = [];
205
+ const privateEvidence = [];
206
+ pushReason(privateReasons, !taskFocused && !disciplined, "no work threshold active");
207
+ pushReason(privateReasons, attachment > 0.58, "attachment keeps private surface viable");
208
+ pushReason(privateReasons, closeness > 0.58, "relational closeness favors private surface");
209
+ pushReason(privateReasons, guardedness > 0.62 || loopPressure > 0.58, "guarded relation state prefers private handling");
210
+ pushReason(privateReasons, repairFriction > 0.48 || residue > 0.45, "carry or friction remains active");
211
+ pushEvidence(privateEvidence, {
212
+ ruleId: "reply-profile.private.default-fallback",
213
+ sourceMetric: "replyProfileBasis",
214
+ rawValue: !taskFocused && !disciplined ? 1 : 0,
215
+ threshold: 1,
216
+ contribution: 0.7,
217
+ condition: !taskFocused && !disciplined,
218
+ });
219
+ pushEvidence(privateEvidence, {
220
+ ruleId: "reply-profile.private.attachment-support",
221
+ sourceMetric: "subjectPlane.attachment",
222
+ rawValue: attachment,
223
+ threshold: 0.58,
224
+ contribution: 0.1,
225
+ condition: attachment > 0.58,
226
+ });
227
+ pushEvidence(privateEvidence, {
228
+ ruleId: "reply-profile.private.closeness-support",
229
+ sourceMetric: "relationPlane.closeness",
230
+ rawValue: closeness,
231
+ threshold: 0.58,
232
+ contribution: 0.08,
233
+ condition: closeness > 0.58,
234
+ });
235
+ pushEvidence(privateEvidence, {
236
+ ruleId: "reply-profile.private.guarded-support",
237
+ sourceMetric: "subjectPlane.guardedness",
238
+ rawValue: guardedness,
239
+ threshold: 0.62,
240
+ contribution: 0.07,
241
+ condition: guardedness > 0.62 || loopPressure > 0.58,
242
+ });
243
+ pushEvidence(privateEvidence, {
244
+ ruleId: "reply-profile.private.carry-support",
245
+ sourceMetric: "subjectPlane.residue",
246
+ rawValue: Math.max(repairFriction, residue),
247
+ threshold: 0.48,
248
+ contribution: 0.05,
249
+ condition: repairFriction > 0.48 || residue > 0.45,
250
+ });
251
+ const privateScore = clamp01(privateEvidence.reduce((sum, item) => sum + item.contribution, 0));
252
+ const selected = responseContract.replyProfile === "work"
253
+ ? "work-profile"
254
+ : "private-profile";
255
+ return {
256
+ selected,
257
+ triggerConditions,
258
+ candidates: [
259
+ {
260
+ candidate: "work-profile",
261
+ score: workScore,
262
+ accepted: selected === "work-profile",
263
+ reasons: workReasons,
264
+ evidence: workEvidence,
265
+ },
266
+ {
267
+ candidate: "private-profile",
268
+ score: privateScore,
269
+ accepted: selected === "private-profile",
270
+ reasons: privateReasons,
271
+ evidence: privateEvidence,
272
+ },
273
+ ],
274
+ };
275
+ }
276
+ function buildCausalChain(state, opts) {
277
+ const relationKey = opts.relationContext?.key ?? "_default";
278
+ const turnRef = `psyche:${relationKey}:turn:${state.meta.totalInteractions}`;
279
+ const parentTurnRef = state.meta.totalInteractions > 1
280
+ ? `psyche:${relationKey}:turn:${state.meta.totalInteractions - 1}`
281
+ : null;
282
+ const continuityRefs = opts.externalContinuityEvents
283
+ .filter((event) => event.kind === "continuity-anchor" || event.kind === "open-loop-anchor")
284
+ .map((event) => event.key);
285
+ const writebackRefs = opts.externalContinuityEvents
286
+ .filter((event) => event.kind === "writeback-calibration")
287
+ .map((event) => event.key);
288
+ const externalTraceRefs = opts.externalContinuityEvents.map((event) => event.key);
289
+ if (opts.writebackFeedback.length > 0 && writebackRefs.length === 0) {
290
+ writebackRefs.push(...opts.writebackFeedback.map((feedback) => `writeback:${relationKey}:${feedback.signal}:${feedback.effect}`));
291
+ }
292
+ if (opts.sessionBridge && continuityRefs.length === 0) {
293
+ continuityRefs.push(`bridge:${relationKey}:${opts.sessionBridge.continuityMode}`);
294
+ }
295
+ return {
296
+ turnRef,
297
+ parentTurnRef,
298
+ continuityRefs,
299
+ writebackRefs,
300
+ externalTraceRefs,
301
+ };
302
+ }
303
+ function buildTraceMapping(externalContinuityEvents) {
304
+ const localTraceRefs = externalContinuityEvents.map((event) => event.key);
305
+ const signalRefs = externalContinuityEvents
306
+ .filter((event) => event.primitive === "signal")
307
+ .map((event) => event.key);
308
+ const traceRefs = externalContinuityEvents
309
+ .filter((event) => event.primitive === "trace")
310
+ .map((event) => event.key);
311
+ const summaryCandidateRefs = externalContinuityEvents
312
+ .filter((event) => event.kind === "continuity-anchor"
313
+ || event.kind === "relation-milestone"
314
+ || (event.kind === "open-loop-anchor" && event.strength >= 0.72))
315
+ .map((event) => event.key);
316
+ return {
317
+ provider: externalContinuityEvents.length > 0 ? "thronglets" : null,
318
+ localTraceRefs,
319
+ signalRefs,
320
+ traceRefs,
321
+ summaryCandidateRefs,
322
+ };
323
+ }
324
+ function listRenderInputs(inputs) {
325
+ const names = [];
326
+ if (inputs.userText)
327
+ names.push("sensing");
328
+ if (inputs.subjectivityContext)
329
+ names.push("subjectivity");
330
+ if (inputs.responseContractContext)
331
+ names.push("response-contract");
332
+ if (inputs.metacognitiveNote)
333
+ names.push("metacognition");
334
+ if (inputs.decisionContext)
335
+ names.push("decision");
336
+ if (inputs.ethicsContext)
337
+ names.push("ethics");
338
+ if (inputs.sharedIntentionalityContext)
339
+ names.push("shared-intentionality");
340
+ if (inputs.experientialNarrative)
341
+ names.push("experiential");
342
+ if (inputs.autonomicDescription)
343
+ names.push("autonomic");
344
+ if (inputs.primarySystemsDescription)
345
+ names.push("primary-systems");
346
+ if (inputs.policyContext)
347
+ names.push("policy");
348
+ return names;
349
+ }
350
+ function listRuntimeHooks(externalContinuityExports, writebackFeedbackCount) {
351
+ const hooks = [
352
+ "appraisal",
353
+ "relation-dynamics",
354
+ "reply-envelope",
355
+ "prompt-renderer",
356
+ ];
357
+ if (writebackFeedbackCount > 0)
358
+ hooks.push("writeback-evaluation");
359
+ if (externalContinuityExports > 0)
360
+ hooks.push("external-continuity");
361
+ return hooks;
362
+ }
363
+ export function buildTurnObservability(state, opts) {
364
+ const stateLayers = buildStateLayers(state, {
365
+ stimulus: opts.stimulus,
366
+ userText: opts.userText,
367
+ sessionBridge: opts.sessionBridge,
368
+ writebackFeedback: opts.writebackFeedback,
369
+ relationContext: opts.relationContext,
370
+ });
371
+ return {
372
+ controlBoundary: pickDominantPlane(opts.replyEnvelope),
373
+ stateLayers,
374
+ stateReconciliation: buildStateReconciliation(stateLayers),
375
+ decisionRationale: buildDecisionRationale(opts.replyEnvelope),
376
+ causalChain: buildCausalChain(state, {
377
+ relationContext: opts.relationContext,
378
+ sessionBridge: opts.sessionBridge,
379
+ writebackFeedback: opts.writebackFeedback,
380
+ externalContinuityEvents: opts.externalContinuityEvents,
381
+ }),
382
+ traceMapping: buildTraceMapping(opts.externalContinuityEvents),
383
+ outputAttribution: {
384
+ canonicalSurface: "reply-envelope",
385
+ promptRenderer: opts.compactMode ? "compact" : "dynamic",
386
+ renderInputs: listRenderInputs(opts.promptRenderInputs),
387
+ runtimeHooks: listRuntimeHooks(opts.externalContinuityEvents.length, opts.writebackFeedback.length),
388
+ externalContinuityExports: opts.externalContinuityEvents.length,
389
+ writebackFeedbackCount: opts.writebackFeedback.length,
390
+ },
391
+ };
392
+ }