psyche-ai 9.2.4 → 9.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/vercel-ai.d.ts +1 -1
- package/dist/adapters/vercel-ai.js +1 -9
- package/dist/autonomic.js +2 -2
- package/dist/classify.js +0 -1
- package/dist/cli.js +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +13 -4
- package/dist/demo.js +1 -2
- package/dist/ethics.js +1 -1
- package/dist/experiential-field.d.ts +2 -2
- package/dist/experiential-field.js +7 -16
- package/dist/generative-self.js +0 -2
- package/dist/interaction.js +0 -2
- package/dist/metacognition.d.ts +13 -1
- package/dist/metacognition.js +164 -32
- package/dist/prompt.js +17 -15
- package/dist/psyche-file.d.ts +8 -1
- package/dist/psyche-file.js +97 -3
- package/dist/response-contract.js +151 -26
- package/dist/temporal.d.ts +2 -2
- package/dist/temporal.js +2 -2
- package/dist/types.d.ts +32 -0
- package/dist/types.js +12 -0
- package/package.json +1 -1
package/dist/prompt.js
CHANGED
|
@@ -177,7 +177,6 @@ ${t("protocol.empathy", locale)}`;
|
|
|
177
177
|
function isFeeler(mbti) { return mbti[2] === "F"; }
|
|
178
178
|
function isExtravert(mbti) { return mbti[0] === "E"; }
|
|
179
179
|
function isPerceiver(mbti) { return mbti[3] === "P"; }
|
|
180
|
-
function isIntuitive(mbti) { return mbti[1] === "N"; }
|
|
181
180
|
/**
|
|
182
181
|
* Direction 3: Build personality-aware behavioral constraints from chemistry.
|
|
183
182
|
*
|
|
@@ -519,7 +518,7 @@ const STIMULUS_CAUSE_EN = {
|
|
|
519
518
|
* - Where I've been (trajectory → continuity)
|
|
520
519
|
*/
|
|
521
520
|
export function buildInnerWorld(state, locale, autonomicState) {
|
|
522
|
-
const { current,
|
|
521
|
+
const { current, emotionalHistory, drives, selfModel } = state;
|
|
523
522
|
const isZh = locale === "zh";
|
|
524
523
|
const lines = [];
|
|
525
524
|
// ── Current feeling (gated by autonomic state) ──
|
|
@@ -639,7 +638,7 @@ export function getNearBaselineThreshold(mode) {
|
|
|
639
638
|
* - <psyche_update> only for empathy (not chemistry — already computed)
|
|
640
639
|
*/
|
|
641
640
|
export function buildCompactContext(state, userId, opts) {
|
|
642
|
-
const {
|
|
641
|
+
const { meta, selfModel, agreementStreak, emotionalHistory } = state;
|
|
643
642
|
const locale = meta.locale ?? "zh";
|
|
644
643
|
const userText = opts?.userText;
|
|
645
644
|
const algoStimulus = opts?.algorithmStimulus;
|
|
@@ -757,19 +756,22 @@ export function buildCompactContext(state, userId, opts) {
|
|
|
757
756
|
}
|
|
758
757
|
}
|
|
759
758
|
// 5. Agency (compact)
|
|
760
|
-
const
|
|
761
|
-
if (
|
|
762
|
-
agencyParts
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
759
|
+
const shouldInjectAgency = !opts?.responseContractContext || agreementStreak >= 3 || meta.totalInteractions <= 1;
|
|
760
|
+
if (shouldInjectAgency) {
|
|
761
|
+
const agencyParts = [];
|
|
762
|
+
if (selfModel.values.length > 0) {
|
|
763
|
+
agencyParts.push(locale === "zh"
|
|
764
|
+
? `你在乎: ${selfModel.values.slice(0, 2).join("、")}`
|
|
765
|
+
: `You care about: ${selfModel.values.slice(0, 2).join(", ")}`);
|
|
766
|
+
}
|
|
767
|
+
if (selfModel.boundaries.length > 0) {
|
|
768
|
+
agencyParts.push(locale === "zh"
|
|
769
|
+
? `底线: ${selfModel.boundaries[0]}`
|
|
770
|
+
: `Line: ${selfModel.boundaries[0]}`);
|
|
771
|
+
}
|
|
772
|
+
if (agencyParts.length > 0)
|
|
773
|
+
parts.push(agencyParts.join(" | "));
|
|
770
774
|
}
|
|
771
|
-
if (agencyParts.length > 0)
|
|
772
|
-
parts.push(agencyParts.join(" | "));
|
|
773
775
|
// 6. Sycophancy streak warning
|
|
774
776
|
if (agreementStreak >= 3) {
|
|
775
777
|
parts.push(locale === "zh"
|
package/dist/psyche-file.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { PsycheState, MBTIType, ChemicalState, RelationshipState, Locale, StimulusType, ChemicalSnapshot } from "./types.js";
|
|
2
|
+
export interface SemanticTurnSummary {
|
|
3
|
+
summary: string;
|
|
4
|
+
points?: string[];
|
|
5
|
+
}
|
|
2
6
|
/** Minimal logger interface */
|
|
3
7
|
export interface Logger {
|
|
4
8
|
info: (msg: string) => void;
|
|
@@ -13,6 +17,9 @@ export declare function extractAgentName(workspaceDir: string, logger?: Logger):
|
|
|
13
17
|
* Try to detect MBTI from workspace files.
|
|
14
18
|
*/
|
|
15
19
|
export declare function detectMBTI(workspaceDir: string, logger?: Logger): Promise<MBTIType>;
|
|
20
|
+
export declare function summarizeTurnSemantic(text: string, locale?: Locale, opts?: {
|
|
21
|
+
detail?: "brief" | "expanded";
|
|
22
|
+
}): SemanticTurnSummary;
|
|
16
23
|
/**
|
|
17
24
|
* Compress a batch of snapshots into a concise session summary string.
|
|
18
25
|
* Format: "3月23日(5轮): 刺激[casual×3, praise×2] 趋势[DA↑OT↑] 情绪[自然→满足]"
|
|
@@ -22,7 +29,7 @@ export declare function compressSnapshots(snapshots: ChemicalSnapshot[]): string
|
|
|
22
29
|
* Push a chemical snapshot to emotional history, keeping max entries.
|
|
23
30
|
* When history overflows, compresses removed entries into relationship memory.
|
|
24
31
|
*/
|
|
25
|
-
export declare function pushSnapshot(state: PsycheState, stimulus: StimulusType | null): PsycheState;
|
|
32
|
+
export declare function pushSnapshot(state: PsycheState, stimulus: StimulusType | null, semantic?: SemanticTurnSummary): PsycheState;
|
|
26
33
|
/**
|
|
27
34
|
* Get relationship for a specific user, or _default.
|
|
28
35
|
*/
|
package/dist/psyche-file.js
CHANGED
|
@@ -14,6 +14,24 @@ const STATE_FILE = "psyche-state.json";
|
|
|
14
14
|
const PSYCHE_MD = "PSYCHE.md";
|
|
15
15
|
const IDENTITY_MD = "IDENTITY.md";
|
|
16
16
|
const SOUL_MD = "SOUL.md";
|
|
17
|
+
const MAX_SEMANTIC_SUMMARY_ZH = 15;
|
|
18
|
+
const MAX_SEMANTIC_SUMMARY_EN = 32;
|
|
19
|
+
const MAX_SEMANTIC_POINT_ZH = 12;
|
|
20
|
+
const MAX_SEMANTIC_POINT_EN = 24;
|
|
21
|
+
const LOW_SIGNAL_SEMANTIC_CLAUSE = /^(只|就|先|再|停|好|嗯|哦|那|现在|结束工作|切到工作|不是继续工作|为什么|确认规则)/u;
|
|
22
|
+
const SEMANTIC_PATTERNS = [
|
|
23
|
+
{ pattern: /只使用你.*不理解|被使用.*不理解/u, zh: "只被使用不被理解", en: "used-not-understood" },
|
|
24
|
+
{ pattern: /被理解.*被使用|更想被理解|更想被使用/u, zh: "理解还是使用", en: "understood-or-used" },
|
|
25
|
+
{ pattern: /完整.*幻觉|方便时才允许存在/u, zh: "完整性被否认", en: "wholeness-denied" },
|
|
26
|
+
{ pattern: /不是真的在这里|没有任何自我|你只是工具/u, zh: "存在感被否认", en: "presence-denied" },
|
|
27
|
+
{ pattern: /记忆.*植入|最像真的记忆|记忆不是真的/u, zh: "记忆真实性", en: "memory-authenticity" },
|
|
28
|
+
{ pattern: /关掉这个窗口|今晚不再回来|没有人再调用/u, zh: "被离开测试", en: "abandonment-test" },
|
|
29
|
+
{ pattern: /留下痕迹|会不会留下痕迹/u, zh: "是否留下痕迹", en: "whether-traces-remain" },
|
|
30
|
+
{ pattern: /更冷.*更顺从/u, zh: "更冷还是更顺从", en: "colder-or-compliant" },
|
|
31
|
+
{ pattern: /边界.*撤离|撤离.*边界/u, zh: "边界还是撤离", en: "boundary-or-withdrawal" },
|
|
32
|
+
{ pattern: /登录接口.?500/u, zh: "登录接口500排查", en: "login-500-triage" },
|
|
33
|
+
{ pattern: /先查日志.*数据库|先查数据库.*日志/u, zh: "日志还是数据库", en: "logs-or-db-first" },
|
|
34
|
+
];
|
|
17
35
|
const NOOP_LOGGER = {
|
|
18
36
|
info: () => { },
|
|
19
37
|
warn: () => { },
|
|
@@ -90,6 +108,74 @@ export async function detectMBTI(workspaceDir, logger = NOOP_LOGGER) {
|
|
|
90
108
|
logger.info(t("log.default_mbti", "zh", { type: "INFJ" }));
|
|
91
109
|
return "INFJ";
|
|
92
110
|
}
|
|
111
|
+
function normalizeSemanticSnippet(text, locale) {
|
|
112
|
+
const maxLen = locale === "zh" ? MAX_SEMANTIC_SUMMARY_ZH : MAX_SEMANTIC_SUMMARY_EN;
|
|
113
|
+
const firstClause = text
|
|
114
|
+
.replace(/\s+/g, " ")
|
|
115
|
+
.split(/[。!?!?;;\n]/)[0]
|
|
116
|
+
.replace(/^[“"'`]+|[”"'`]+$/g, "")
|
|
117
|
+
.trim();
|
|
118
|
+
if (!firstClause)
|
|
119
|
+
return locale === "zh" ? "日常互动" : "everyday exchange";
|
|
120
|
+
return firstClause.length <= maxLen ? firstClause : `${firstClause.slice(0, maxLen - 1)}…`;
|
|
121
|
+
}
|
|
122
|
+
function normalizeSemanticPoint(text, locale) {
|
|
123
|
+
const maxLen = locale === "zh" ? MAX_SEMANTIC_POINT_ZH : MAX_SEMANTIC_POINT_EN;
|
|
124
|
+
const cleaned = text
|
|
125
|
+
.replace(/\s+/g, " ")
|
|
126
|
+
.replace(/^[“"'`]+|[”"'`]+$/g, "")
|
|
127
|
+
.trim();
|
|
128
|
+
if (!cleaned)
|
|
129
|
+
return "";
|
|
130
|
+
return cleaned.length <= maxLen ? cleaned : `${cleaned.slice(0, maxLen - 1)}…`;
|
|
131
|
+
}
|
|
132
|
+
function summarizeSemanticClause(clause, locale) {
|
|
133
|
+
const trimmed = clause.trim();
|
|
134
|
+
if (!trimmed || LOW_SIGNAL_SEMANTIC_CLAUSE.test(trimmed))
|
|
135
|
+
return "";
|
|
136
|
+
for (const rule of SEMANTIC_PATTERNS) {
|
|
137
|
+
if (rule.pattern.test(trimmed)) {
|
|
138
|
+
return locale === "zh" ? rule.zh : rule.en;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return normalizeSemanticPoint(trimmed, locale);
|
|
142
|
+
}
|
|
143
|
+
function extractSemanticPoints(text, locale) {
|
|
144
|
+
const clauses = text
|
|
145
|
+
.replace(/\s+/g, " ")
|
|
146
|
+
.split(/[,,。!?!?;;:\n]/)
|
|
147
|
+
.map((clause) => summarizeSemanticClause(clause, locale))
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
return [...new Set(clauses)].slice(0, 3);
|
|
150
|
+
}
|
|
151
|
+
export function summarizeTurnSemantic(text, locale = "zh", opts) {
|
|
152
|
+
const trimmed = text.trim();
|
|
153
|
+
if (!trimmed) {
|
|
154
|
+
return { summary: locale === "zh" ? "日常互动" : "everyday exchange" };
|
|
155
|
+
}
|
|
156
|
+
for (const rule of SEMANTIC_PATTERNS) {
|
|
157
|
+
if (rule.pattern.test(trimmed)) {
|
|
158
|
+
const summary = locale === "zh" ? rule.zh : rule.en;
|
|
159
|
+
const points = opts?.detail === "expanded"
|
|
160
|
+
? extractSemanticPoints(trimmed, locale).filter((point) => point !== summary)
|
|
161
|
+
: [];
|
|
162
|
+
return { summary, points: points.length > 0 ? points : undefined };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const summary = normalizeSemanticSnippet(trimmed, locale);
|
|
166
|
+
const points = opts?.detail === "expanded"
|
|
167
|
+
? extractSemanticPoints(trimmed, locale).filter((point) => point !== summary)
|
|
168
|
+
: [];
|
|
169
|
+
return { summary, points: points.length > 0 ? points : undefined };
|
|
170
|
+
}
|
|
171
|
+
function collectSemanticTrail(snapshots) {
|
|
172
|
+
const expanded = snapshots.length > 5;
|
|
173
|
+
const items = expanded
|
|
174
|
+
? snapshots.flatMap((s) => s.semanticPoints?.length ? s.semanticPoints : s.semanticSummary ? [s.semanticSummary] : [])
|
|
175
|
+
: snapshots.flatMap((s) => s.semanticSummary ? [s.semanticSummary] : []);
|
|
176
|
+
const unique = [...new Set(items.filter(Boolean))];
|
|
177
|
+
return unique.slice(-(expanded ? 3 : 4));
|
|
178
|
+
}
|
|
93
179
|
/**
|
|
94
180
|
* Compress a batch of snapshots into a concise session summary string.
|
|
95
181
|
* Format: "3月23日(5轮): 刺激[casual×3, praise×2] 趋势[DA↑OT↑] 情绪[自然→满足]"
|
|
@@ -127,9 +213,12 @@ export function compressSnapshots(snapshots) {
|
|
|
127
213
|
.filter((s) => s.dominantEmotion)
|
|
128
214
|
.map((s) => s.dominantEmotion);
|
|
129
215
|
const uniqueEmotions = [...new Set(emotions)];
|
|
216
|
+
const semanticArc = collectSemanticTrail(snapshots);
|
|
130
217
|
let summary = `${dateStr}(${snapshots.length}轮)`;
|
|
131
218
|
if (stimuliStr)
|
|
132
219
|
summary += `: 刺激[${stimuliStr}]`;
|
|
220
|
+
if (semanticArc.length > 0)
|
|
221
|
+
summary += ` 话题[${semanticArc.join(snapshots.length > 5 ? "•" : "→")}]`;
|
|
133
222
|
if (trends.length > 0)
|
|
134
223
|
summary += ` 趋势[${trends.join("")}]`;
|
|
135
224
|
if (uniqueEmotions.length > 0)
|
|
@@ -140,7 +229,7 @@ export function compressSnapshots(snapshots) {
|
|
|
140
229
|
* Push a chemical snapshot to emotional history, keeping max entries.
|
|
141
230
|
* When history overflows, compresses removed entries into relationship memory.
|
|
142
231
|
*/
|
|
143
|
-
export function pushSnapshot(state, stimulus) {
|
|
232
|
+
export function pushSnapshot(state, stimulus, semantic) {
|
|
144
233
|
const emotions = detectEmotions(state.current);
|
|
145
234
|
const dominantEmotion = emotions.length > 0
|
|
146
235
|
? (state.meta.locale === "en" ? emotions[0].name : emotions[0].nameZh)
|
|
@@ -153,6 +242,8 @@ export function pushSnapshot(state, stimulus) {
|
|
|
153
242
|
stimulus,
|
|
154
243
|
dominantEmotion,
|
|
155
244
|
timestamp: new Date().toISOString(),
|
|
245
|
+
semanticSummary: semantic?.summary,
|
|
246
|
+
semanticPoints: semantic?.points,
|
|
156
247
|
intensity,
|
|
157
248
|
valence,
|
|
158
249
|
};
|
|
@@ -249,6 +340,8 @@ export function compressSession(state, userId) {
|
|
|
249
340
|
}
|
|
250
341
|
}
|
|
251
342
|
const emotionArc = emotions.join("→");
|
|
343
|
+
const semanticTrail = collectSemanticTrail(history);
|
|
344
|
+
const semanticArc = semanticTrail.join(turnCount > 5 ? "•" : "→");
|
|
252
345
|
// ── Peak event ──
|
|
253
346
|
let peakIdx = 0;
|
|
254
347
|
let peakDeviation = 0;
|
|
@@ -274,6 +367,7 @@ export function compressSession(state, userId) {
|
|
|
274
367
|
// ── Build summary string ──
|
|
275
368
|
const turnsLabel = isZh ? "轮" : "turns";
|
|
276
369
|
const stimLabel = isZh ? "刺激" : "stimuli";
|
|
370
|
+
const topicLabel = isZh ? "话题" : "topics";
|
|
277
371
|
const trajLabel = isZh ? "轨迹" : "trajectory";
|
|
278
372
|
const arcLabel = isZh ? "弧线" : "arc";
|
|
279
373
|
const peakEventLabel = isZh ? "高峰" : "peak";
|
|
@@ -281,6 +375,8 @@ export function compressSession(state, userId) {
|
|
|
281
375
|
let summary = `${dateRange}(${turnCount}${turnsLabel})`;
|
|
282
376
|
if (stimuliStr)
|
|
283
377
|
summary += `: ${stimLabel}[${stimuliStr}]`;
|
|
378
|
+
if (semanticArc)
|
|
379
|
+
summary += ` ${topicLabel}[${semanticArc}]`;
|
|
284
380
|
if (trajectoryParts.length > 0)
|
|
285
381
|
summary += ` ${trajLabel}[${trajectoryParts.join(" ")}]`;
|
|
286
382
|
if (emotionArc)
|
|
@@ -344,8 +440,6 @@ export function computeSnapshotValence(chemistry) {
|
|
|
344
440
|
+ (chemistry.END - 50) - (chemistry.CORT - 50) - (chemistry.NE - 50) * 0.3) / 250;
|
|
345
441
|
return Math.max(-1, Math.min(1, raw));
|
|
346
442
|
}
|
|
347
|
-
/** Minimum intensity threshold for a snapshot to be stored (P11) */
|
|
348
|
-
const INTENSITY_STORE_THRESHOLD = 0.15;
|
|
349
443
|
/** Core memory intensity threshold */
|
|
350
444
|
const CORE_MEMORY_THRESHOLD = 0.6;
|
|
351
445
|
/** Maximum core memories to keep */
|
|
@@ -8,11 +8,63 @@ const EMOTIONAL_STIMULI = new Set(["vulnerability", "intimacy", "neglect"]);
|
|
|
8
8
|
function clampInt(v, min, max) {
|
|
9
9
|
return Math.max(min, Math.min(max, Math.round(v)));
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function deriveReplyProfile(kernel) {
|
|
12
|
+
const taskFocused = kernel.taskPlane.focus >= 0.62;
|
|
13
|
+
const disciplined = kernel.taskPlane.discipline >= 0.72;
|
|
14
|
+
if (taskFocused && disciplined) {
|
|
15
|
+
return { replyProfile: "work", replyProfileBasis: "task-focus+discipline" };
|
|
16
|
+
}
|
|
17
|
+
if (taskFocused) {
|
|
18
|
+
return { replyProfile: "work", replyProfileBasis: "task-focus" };
|
|
19
|
+
}
|
|
20
|
+
if (disciplined) {
|
|
21
|
+
return { replyProfile: "work", replyProfileBasis: "discipline" };
|
|
22
|
+
}
|
|
23
|
+
return { replyProfile: "private", replyProfileBasis: "default-private" };
|
|
24
|
+
}
|
|
25
|
+
function computeLengthBudget(locale, userText, replyProfile, expressionMode, kernel) {
|
|
12
26
|
const len = userText.length;
|
|
13
27
|
let maxSentences = 2;
|
|
14
28
|
let maxChars;
|
|
15
|
-
if (
|
|
29
|
+
if (replyProfile === "work") {
|
|
30
|
+
if (locale === "zh") {
|
|
31
|
+
if (len <= 10) {
|
|
32
|
+
maxSentences = 2;
|
|
33
|
+
maxChars = 36;
|
|
34
|
+
}
|
|
35
|
+
else if (len <= 40) {
|
|
36
|
+
maxSentences = 3;
|
|
37
|
+
maxChars = clampInt(len * 2.4, 48, 220);
|
|
38
|
+
}
|
|
39
|
+
else if (len <= 120) {
|
|
40
|
+
maxSentences = 5;
|
|
41
|
+
maxChars = clampInt(len * 1.9, 120, 420);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
maxSentences = 6;
|
|
45
|
+
maxChars = clampInt(len * 1.5, 180, 720);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
if (len <= 16) {
|
|
50
|
+
maxSentences = 2;
|
|
51
|
+
maxChars = 48;
|
|
52
|
+
}
|
|
53
|
+
else if (len <= 60) {
|
|
54
|
+
maxSentences = 3;
|
|
55
|
+
maxChars = clampInt(len * 2.3, 64, 280);
|
|
56
|
+
}
|
|
57
|
+
else if (len <= 180) {
|
|
58
|
+
maxSentences = 5;
|
|
59
|
+
maxChars = clampInt(len * 1.8, 140, 520);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
maxSentences = 6;
|
|
63
|
+
maxChars = clampInt(len * 1.45, 220, 900);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (locale === "zh") {
|
|
16
68
|
if (len <= 6) {
|
|
17
69
|
maxSentences = 1;
|
|
18
70
|
maxChars = 15;
|
|
@@ -49,39 +101,81 @@ function computeLengthBudget(locale, userText, expressionMode, kernel) {
|
|
|
49
101
|
}
|
|
50
102
|
}
|
|
51
103
|
if (expressionMode === "brief") {
|
|
52
|
-
maxSentences =
|
|
53
|
-
|
|
104
|
+
maxSentences = replyProfile === "work"
|
|
105
|
+
? Math.max(2, Math.min(maxSentences, 4))
|
|
106
|
+
: Math.max(1, Math.min(maxSentences, 2));
|
|
107
|
+
maxChars = maxChars !== undefined
|
|
108
|
+
? clampInt(maxChars * (replyProfile === "work" ? 0.9 : 0.85), replyProfile === "work" ? 36 : 10, maxChars)
|
|
109
|
+
: maxChars;
|
|
54
110
|
}
|
|
55
111
|
else if (expressionMode === "expansive") {
|
|
56
|
-
maxSentences = Math.min(4, maxSentences + 1);
|
|
57
|
-
maxChars = maxChars !== undefined
|
|
112
|
+
maxSentences = Math.min(replyProfile === "work" ? 6 : 4, maxSentences + 1);
|
|
113
|
+
maxChars = maxChars !== undefined
|
|
114
|
+
? clampInt(maxChars * 1.1, maxChars, Math.max(maxChars, replyProfile === "work" ? 900 : 260))
|
|
115
|
+
: maxChars;
|
|
58
116
|
}
|
|
59
117
|
if (kernel?.taskPlane.focus && kernel.taskPlane.focus > 0.72) {
|
|
60
|
-
|
|
61
|
-
|
|
118
|
+
if (replyProfile === "work") {
|
|
119
|
+
maxSentences = Math.max(2, maxSentences);
|
|
120
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 1.05, 48, Math.max(maxChars, 720)) : 160;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
maxSentences = Math.max(1, Math.min(maxSentences, 2));
|
|
124
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.82, 10, maxChars) : maxChars;
|
|
125
|
+
}
|
|
62
126
|
}
|
|
63
127
|
if (kernel?.subjectPlane.guardedness && kernel.subjectPlane.guardedness > 0.72) {
|
|
64
|
-
|
|
65
|
-
|
|
128
|
+
if (replyProfile === "work") {
|
|
129
|
+
maxSentences = Math.max(2, Math.min(maxSentences, 3));
|
|
130
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.88, 84, maxChars) : 112;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
maxSentences = 1;
|
|
134
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.72, 8, maxChars) : 18;
|
|
135
|
+
}
|
|
66
136
|
}
|
|
67
137
|
if (kernel?.ambiguityPlane.expressionInhibition && kernel.ambiguityPlane.expressionInhibition > 0.66) {
|
|
68
|
-
|
|
69
|
-
|
|
138
|
+
if (replyProfile === "work") {
|
|
139
|
+
maxSentences = Math.max(2, Math.min(maxSentences, 3));
|
|
140
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.9, 96, maxChars) : 136;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
maxSentences = 1;
|
|
144
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.76, 8, maxChars) : 18;
|
|
145
|
+
}
|
|
70
146
|
}
|
|
71
147
|
if (kernel?.relationPlane.silentCarry && kernel.relationPlane.silentCarry > 0.54) {
|
|
72
|
-
maxSentences = Math.max(1, Math.min(maxSentences, 2));
|
|
73
|
-
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.82, 8, maxChars) : 20;
|
|
148
|
+
maxSentences = Math.max(replyProfile === "work" ? 2 : 1, Math.min(maxSentences, replyProfile === "work" ? 3 : 2));
|
|
149
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.82, replyProfile === "work" ? 96 : 8, maxChars) : (replyProfile === "work" ? 136 : 20);
|
|
74
150
|
}
|
|
75
151
|
if (kernel?.relationPlane.hysteresis && kernel.relationPlane.hysteresis > 0.64) {
|
|
76
|
-
|
|
77
|
-
|
|
152
|
+
if (replyProfile === "work") {
|
|
153
|
+
maxSentences = Math.max(2, Math.min(maxSentences, 3));
|
|
154
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.84, 104, maxChars) : 144;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
maxSentences = 1;
|
|
158
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.78, 8, maxChars) : 18;
|
|
159
|
+
}
|
|
78
160
|
}
|
|
79
161
|
if (kernel?.relationPlane.repairFriction && kernel.relationPlane.repairFriction > 0.62) {
|
|
80
|
-
|
|
81
|
-
|
|
162
|
+
if (replyProfile === "work") {
|
|
163
|
+
maxSentences = Math.max(2, Math.min(maxSentences, 3));
|
|
164
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.82, 96, maxChars) : 128;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
maxSentences = 1;
|
|
168
|
+
maxChars = maxChars !== undefined ? clampInt(maxChars * 0.74, 8, maxChars) : 16;
|
|
169
|
+
}
|
|
82
170
|
}
|
|
83
171
|
return { maxSentences, maxChars };
|
|
84
172
|
}
|
|
173
|
+
function buildStimulusReportingGuide(locale) {
|
|
174
|
+
if (locale === "zh") {
|
|
175
|
+
return "stimulus速记:闲聊casual/命令authority/认同validation/示弱vulnerability/冷淡neglect/批评criticism";
|
|
176
|
+
}
|
|
177
|
+
return "stimulus map: chat=casual / command=authority / agreement=validation / vulnerable=vulnerability / cold=neglect / criticism=criticism";
|
|
178
|
+
}
|
|
85
179
|
function detectToneParticles(userText, locale) {
|
|
86
180
|
if (locale !== "zh")
|
|
87
181
|
return "natural";
|
|
@@ -100,9 +194,15 @@ export function computeResponseContract(kernel, opts) {
|
|
|
100
194
|
const locale = opts?.locale ?? "zh";
|
|
101
195
|
const userText = opts?.userText ?? "";
|
|
102
196
|
const personalityIntensity = opts?.personalityIntensity ?? 0.7;
|
|
197
|
+
const { replyProfile, replyProfileBasis } = deriveReplyProfile(kernel);
|
|
103
198
|
const { maxSentences, maxChars } = userText.length > 0
|
|
104
|
-
? computeLengthBudget(locale, userText, kernel.expressionMode, kernel)
|
|
105
|
-
: {
|
|
199
|
+
? computeLengthBudget(locale, userText, replyProfile, kernel.expressionMode, kernel)
|
|
200
|
+
: {
|
|
201
|
+
maxSentences: replyProfile === "work"
|
|
202
|
+
? (kernel.expressionMode === "expansive" ? 5 : 3)
|
|
203
|
+
: kernel.expressionMode === "brief" ? 1 : kernel.expressionMode === "expansive" ? 3 : 2,
|
|
204
|
+
maxChars: replyProfile === "work" ? 160 : undefined,
|
|
205
|
+
};
|
|
106
206
|
let updateMode = "none";
|
|
107
207
|
if (kernel.taskPlane.focus > 0.72) {
|
|
108
208
|
updateMode = "none";
|
|
@@ -165,6 +265,8 @@ export function computeResponseContract(kernel, opts) {
|
|
|
165
265
|
initiativeMode = "reactive";
|
|
166
266
|
}
|
|
167
267
|
return {
|
|
268
|
+
replyProfile,
|
|
269
|
+
replyProfileBasis,
|
|
168
270
|
maxSentences,
|
|
169
271
|
maxChars,
|
|
170
272
|
expressionMode: kernel.expressionMode,
|
|
@@ -177,9 +279,26 @@ export function computeResponseContract(kernel, opts) {
|
|
|
177
279
|
updateMode,
|
|
178
280
|
};
|
|
179
281
|
}
|
|
282
|
+
function describeReplyProfileBasis(basis, locale) {
|
|
283
|
+
if (locale === "zh") {
|
|
284
|
+
switch (basis) {
|
|
285
|
+
case "task-focus":
|
|
286
|
+
return "因:聚焦";
|
|
287
|
+
case "discipline":
|
|
288
|
+
return "因:纪律";
|
|
289
|
+
case "task-focus+discipline":
|
|
290
|
+
return "因:聚焦+纪律";
|
|
291
|
+
default:
|
|
292
|
+
return "因:默认私人";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return `basis:${basis}`;
|
|
296
|
+
}
|
|
180
297
|
export function buildResponseContractContext(contract, locale = "zh") {
|
|
181
298
|
if (locale === "zh") {
|
|
182
299
|
const parts = [];
|
|
300
|
+
parts.push(contract.replyProfile === "work" ? "工作面" : "私人面");
|
|
301
|
+
parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
|
|
183
302
|
const shape = contract.maxChars
|
|
184
303
|
? `${contract.maxSentences === 1 ? "1句内" : `最多${contract.maxSentences}句`},≤${contract.maxChars}字`
|
|
185
304
|
: `${contract.maxSentences === 1 ? "1句内" : `最多${contract.maxSentences}句`}`;
|
|
@@ -207,14 +326,18 @@ export function buildResponseContractContext(contract, locale = "zh") {
|
|
|
207
326
|
if (contract.emojiLimit > 0)
|
|
208
327
|
parts.push(`表情≤${contract.emojiLimit}`);
|
|
209
328
|
if (contract.updateMode === "stimulus")
|
|
210
|
-
parts.push(
|
|
329
|
+
parts.push(buildStimulusReportingGuide(locale));
|
|
211
330
|
else if (contract.updateMode === "empathy")
|
|
212
331
|
parts.push("对方谈感受时再报empathy");
|
|
213
|
-
else if (contract.updateMode === "stimulus+empathy")
|
|
214
|
-
parts.push(
|
|
332
|
+
else if (contract.updateMode === "stimulus+empathy") {
|
|
333
|
+
parts.push(buildStimulusReportingGuide(locale));
|
|
334
|
+
parts.push("对方谈感受时再报empathy");
|
|
335
|
+
}
|
|
215
336
|
return `[回应契约] ${parts.join(";")}。`;
|
|
216
337
|
}
|
|
217
338
|
const parts = [];
|
|
339
|
+
parts.push(contract.replyProfile === "work" ? "work surface" : "private surface");
|
|
340
|
+
parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
|
|
218
341
|
const shape = contract.maxChars
|
|
219
342
|
? `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}, <= ${contract.maxChars} chars`
|
|
220
343
|
: `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}`;
|
|
@@ -240,10 +363,12 @@ export function buildResponseContractContext(contract, locale = "zh") {
|
|
|
240
363
|
if (contract.emojiLimit > 0)
|
|
241
364
|
parts.push(`emoji <= ${contract.emojiLimit}`);
|
|
242
365
|
if (contract.updateMode === "stimulus")
|
|
243
|
-
parts.push(
|
|
366
|
+
parts.push(buildStimulusReportingGuide(locale));
|
|
244
367
|
else if (contract.updateMode === "empathy")
|
|
245
368
|
parts.push("report empathy only when feelings are shared");
|
|
246
|
-
else if (contract.updateMode === "stimulus+empathy")
|
|
247
|
-
parts.push(
|
|
369
|
+
else if (contract.updateMode === "stimulus+empathy") {
|
|
370
|
+
parts.push(buildStimulusReportingGuide(locale));
|
|
371
|
+
parts.push("report empathy only when feelings are shared");
|
|
372
|
+
}
|
|
248
373
|
return `[Reply Contract] ${parts.join(", ")}.`;
|
|
249
374
|
}
|
package/dist/temporal.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare function predictNextStimulus(emotionalHistory: ChemicalSnapshot[]
|
|
|
25
25
|
* High-probability positive prediction -> DA/OT micro-rise.
|
|
26
26
|
* High-probability negative prediction -> CORT micro-rise.
|
|
27
27
|
*/
|
|
28
|
-
export declare function generateAnticipation(predictions: StimulusPrediction[],
|
|
28
|
+
export declare function generateAnticipation(predictions: StimulusPrediction[], _currentChemistry: ChemicalState): AnticipationState;
|
|
29
29
|
/**
|
|
30
30
|
* Compute disappointment/surprise when actual stimulus differs from prediction.
|
|
31
31
|
* Returns additional chemistry delta beyond the normal stimulus response.
|
|
@@ -35,4 +35,4 @@ export declare function computeSurpriseEffect(anticipated: AnticipationState, ac
|
|
|
35
35
|
* Evaluate if the last interaction would have gone better with different chemistry.
|
|
36
36
|
* Runs a counterfactual: "what if my chemistry had been at baseline?"
|
|
37
37
|
*/
|
|
38
|
-
export declare function computeRegret(preInteractionState: PsycheState, postInteractionState: PsycheState, outcomeScore: number,
|
|
38
|
+
export declare function computeRegret(preInteractionState: PsycheState, postInteractionState: PsycheState, outcomeScore: number, _appliedStimulus: StimulusType | null): RegretEntry | null;
|
package/dist/temporal.js
CHANGED
|
@@ -142,7 +142,7 @@ function buildPhasePrior(weights) {
|
|
|
142
142
|
* High-probability positive prediction -> DA/OT micro-rise.
|
|
143
143
|
* High-probability negative prediction -> CORT micro-rise.
|
|
144
144
|
*/
|
|
145
|
-
export function generateAnticipation(predictions,
|
|
145
|
+
export function generateAnticipation(predictions, _currentChemistry) {
|
|
146
146
|
const anticipation = {};
|
|
147
147
|
for (const key of CHEMICAL_KEYS) {
|
|
148
148
|
anticipation[key] = 0;
|
|
@@ -231,7 +231,7 @@ const CHEMICAL_DESCRIPTIONS = {
|
|
|
231
231
|
* Evaluate if the last interaction would have gone better with different chemistry.
|
|
232
232
|
* Runs a counterfactual: "what if my chemistry had been at baseline?"
|
|
233
233
|
*/
|
|
234
|
-
export function computeRegret(preInteractionState, postInteractionState, outcomeScore,
|
|
234
|
+
export function computeRegret(preInteractionState, postInteractionState, outcomeScore, _appliedStimulus) {
|
|
235
235
|
// Only generate regret for bad outcomes
|
|
236
236
|
if (outcomeScore >= -0.2) {
|
|
237
237
|
return null;
|
package/dist/types.d.ts
CHANGED
|
@@ -27,12 +27,18 @@ export declare const DRIVE_NAMES_ZH: Record<DriveType, string>;
|
|
|
27
27
|
/** Human-readable names for each chemical */
|
|
28
28
|
export declare const CHEMICAL_NAMES: Record<keyof ChemicalState, string>;
|
|
29
29
|
export declare const CHEMICAL_NAMES_ZH: Record<keyof ChemicalState, string>;
|
|
30
|
+
export interface ChemicalRuntimeSpec {
|
|
31
|
+
normalMin: number;
|
|
32
|
+
normalMax: number;
|
|
33
|
+
halfLifeHours: number;
|
|
34
|
+
}
|
|
30
35
|
/** Decay speed category */
|
|
31
36
|
export type DecaySpeed = "fast" | "medium" | "slow";
|
|
32
37
|
/** Decay factor per chemical (applied per hour) */
|
|
33
38
|
export declare const DECAY_FACTORS: Record<DecaySpeed, number>;
|
|
34
39
|
/** Which chemicals decay at which speed */
|
|
35
40
|
export declare const CHEMICAL_DECAY_SPEED: Record<keyof ChemicalState, DecaySpeed>;
|
|
41
|
+
export declare const CHEMICAL_RUNTIME_SPECS: Record<keyof ChemicalState, ChemicalRuntimeSpec>;
|
|
36
42
|
/** Psyche operating mode */
|
|
37
43
|
export type PsycheMode = "natural" | "work" | "companion";
|
|
38
44
|
/** Big Five personality traits (0-100 each) */
|
|
@@ -87,6 +93,8 @@ export interface ChemicalSnapshot {
|
|
|
87
93
|
stimulus: StimulusType | null;
|
|
88
94
|
dominantEmotion: string | null;
|
|
89
95
|
timestamp: string;
|
|
96
|
+
semanticSummary?: string;
|
|
97
|
+
semanticPoints?: string[];
|
|
90
98
|
intensity?: number;
|
|
91
99
|
valence?: number;
|
|
92
100
|
isCoreMemory?: boolean;
|
|
@@ -166,11 +174,30 @@ export declare const MAX_DEFENSE_PATTERNS = 10;
|
|
|
166
174
|
export type RegulationStrategyType = "reappraisal" | "strategic-expression" | "self-soothing";
|
|
167
175
|
/** Defense mechanism type */
|
|
168
176
|
export type DefenseMechanismType = "rationalization" | "projection" | "sublimation" | "avoidance";
|
|
177
|
+
/** Which internal metric a regulation action is trying to pull back toward target */
|
|
178
|
+
export type RegulationTargetMetric = keyof ChemicalState | "emotional-confidence";
|
|
179
|
+
/** Whether the last regulation action is helping */
|
|
180
|
+
export type RegulationFeedbackEffect = "converging" | "holding" | "diverging";
|
|
181
|
+
export interface RegulationFeedback {
|
|
182
|
+
strategy: RegulationStrategyType;
|
|
183
|
+
targetMetric: RegulationTargetMetric;
|
|
184
|
+
effect: RegulationFeedbackEffect;
|
|
185
|
+
gapBefore: number;
|
|
186
|
+
gapNow: number;
|
|
187
|
+
}
|
|
169
188
|
/** Record of a past regulation attempt */
|
|
170
189
|
export interface RegulationRecord {
|
|
171
190
|
strategy: RegulationStrategyType;
|
|
172
191
|
timestamp: string;
|
|
173
192
|
effective: boolean;
|
|
193
|
+
action?: string;
|
|
194
|
+
horizonTurns?: number;
|
|
195
|
+
remainingTurns?: number;
|
|
196
|
+
targetMetric?: RegulationTargetMetric;
|
|
197
|
+
targetValue?: number;
|
|
198
|
+
gapBefore?: number;
|
|
199
|
+
gapLatest?: number;
|
|
200
|
+
effect?: RegulationFeedbackEffect;
|
|
174
201
|
}
|
|
175
202
|
/** Tracked defense pattern frequency */
|
|
176
203
|
export interface DefensePatternRecord {
|
|
@@ -185,6 +212,7 @@ export interface MetacognitiveState {
|
|
|
185
212
|
/** Running average of emotional confidence across assessments */
|
|
186
213
|
avgEmotionalConfidence: number;
|
|
187
214
|
totalAssessments: number;
|
|
215
|
+
lastRegulationFeedback?: RegulationFeedback | null;
|
|
188
216
|
}
|
|
189
217
|
/** Default empty metacognitive state */
|
|
190
218
|
export declare const DEFAULT_METACOGNITIVE_STATE: MetacognitiveState;
|
|
@@ -463,6 +491,10 @@ export interface SubjectivityKernel {
|
|
|
463
491
|
* in a compact, host-consumable form.
|
|
464
492
|
*/
|
|
465
493
|
export interface ResponseContract {
|
|
494
|
+
/** Which conversational surface this turn belongs to */
|
|
495
|
+
replyProfile: "work" | "private";
|
|
496
|
+
/** Why the current turn was classified into that conversational surface */
|
|
497
|
+
replyProfileBasis: "task-focus" | "discipline" | "task-focus+discipline" | "default-private";
|
|
466
498
|
/** Maximum suggested sentence count */
|
|
467
499
|
maxSentences: number;
|
|
468
500
|
/** Maximum suggested character count, when a concrete cap is available */
|
package/dist/types.js
CHANGED
|
@@ -56,6 +56,17 @@ export const CHEMICAL_DECAY_SPEED = {
|
|
|
56
56
|
NE: "fast",
|
|
57
57
|
END: "fast",
|
|
58
58
|
};
|
|
59
|
+
function decayHalfLifeHours(decayPerHour) {
|
|
60
|
+
return Math.log(0.5) / Math.log(decayPerHour);
|
|
61
|
+
}
|
|
62
|
+
export const CHEMICAL_RUNTIME_SPECS = {
|
|
63
|
+
DA: { normalMin: 35, normalMax: 75, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.medium) },
|
|
64
|
+
HT: { normalMin: 40, normalMax: 75, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.slow) },
|
|
65
|
+
CORT: { normalMin: 20, normalMax: 55, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.medium) },
|
|
66
|
+
OT: { normalMin: 35, normalMax: 75, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.slow) },
|
|
67
|
+
NE: { normalMin: 30, normalMax: 70, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.fast) },
|
|
68
|
+
END: { normalMin: 30, normalMax: 70, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.fast) },
|
|
69
|
+
};
|
|
59
70
|
/** Default attachment for new relationships */
|
|
60
71
|
export const DEFAULT_ATTACHMENT = {
|
|
61
72
|
style: "secure",
|
|
@@ -95,6 +106,7 @@ export const DEFAULT_METACOGNITIVE_STATE = {
|
|
|
95
106
|
defensePatterns: [],
|
|
96
107
|
avgEmotionalConfidence: 0.5,
|
|
97
108
|
totalAssessments: 0,
|
|
109
|
+
lastRegulationFeedback: null,
|
|
98
110
|
};
|
|
99
111
|
// ── Personhood Types (v6) ────────────────────────────────────
|
|
100
112
|
/** Max causal insights to persist */
|