psyche-ai 10.0.0 → 10.0.2
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/appraisal.js +2 -2
- package/dist/core.js +4 -3
- package/dist/host-controls.js +12 -16
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/prompt.js +18 -18
- package/dist/relation-dynamics.js +5 -5
- package/dist/reply-envelope.js +1 -0
- package/dist/response-contract.d.ts +1 -0
- package/dist/response-contract.js +32 -10
- package/dist/types.d.ts +16 -0
- package/dist/types.js +44 -0
- package/package.json +1 -1
package/dist/appraisal.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Zero-LLM, low-latency detection of self-relevant semantic pressure.
|
|
5
5
|
// These axes sit beneath prompt prose and above raw stimulus labels.
|
|
6
6
|
// ============================================================
|
|
7
|
-
import { DEFAULT_APPRAISAL_AXES } from "./types.js";
|
|
7
|
+
import { DEFAULT_APPRAISAL_AXES, MODE_PROFILES } from "./types.js";
|
|
8
8
|
import { detectIntent } from "./classify.js";
|
|
9
9
|
function clamp01(v) {
|
|
10
10
|
return Math.max(0, Math.min(1, v));
|
|
@@ -334,7 +334,7 @@ export function mergeAppraisalResidue(previous, current, mode) {
|
|
|
334
334
|
return next;
|
|
335
335
|
}
|
|
336
336
|
function getAxisDecay(key, mode, previousValue, currentValue) {
|
|
337
|
-
let decay = mode
|
|
337
|
+
let decay = MODE_PROFILES[mode ?? "natural"].appraisalDecay;
|
|
338
338
|
if (key === "identityThreat" || key === "abandonmentRisk" || key === "selfPreservation") {
|
|
339
339
|
decay += 0.08;
|
|
340
340
|
}
|
package/dist/core.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
//
|
|
12
12
|
// Orchestrates: chemistry, classify, prompt, profiles, guards, learning
|
|
13
13
|
// ============================================================
|
|
14
|
-
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD } from "./types.js";
|
|
14
|
+
import { DEFAULT_RELATIONSHIP, DEFAULT_DRIVES, DEFAULT_LEARNING_STATE, DEFAULT_METACOGNITIVE_STATE, DEFAULT_PERSONHOOD_STATE, DEFAULT_ENERGY_BUDGETS, DEFAULT_TRAIT_DRIFT, DEFAULT_SUBJECT_RESIDUE, DEFAULT_DYADIC_FIELD, MODE_PROFILES } from "./types.js";
|
|
15
15
|
import { MemoryStorageAdapter } from "./storage.js";
|
|
16
16
|
import { applyDecay, applyStimulus, applyContagion, clamp, describeEmotionalState } from "./chemistry.js";
|
|
17
17
|
import { classifyStimulus, BuiltInClassifier, buildLLMClassifierPrompt, parseLLMClassification } from "./classify.js";
|
|
@@ -342,8 +342,9 @@ export class PsycheEngine {
|
|
|
342
342
|
// hits ~1.7x harder than a 0.55 mild disagreement.
|
|
343
343
|
// Maps [0.5, 1.0] → [0.6, 1.2] via linear interpolation.
|
|
344
344
|
const confidenceIntensity = 0.6 + (primary.confidence - 0.5) * 1.2;
|
|
345
|
-
const
|
|
346
|
-
const
|
|
345
|
+
const modeProfile = MODE_PROFILES[this.cfg.mode];
|
|
346
|
+
const modeMultiplier = modeProfile.chemistryMultiplier;
|
|
347
|
+
const effectiveMaxDelta = modeProfile.maxChemicalDelta ?? this.cfg.maxChemicalDelta;
|
|
347
348
|
// v9: Habituation — count recent same-type stimuli in this session
|
|
348
349
|
const recentSameCount = (state.emotionalHistory ?? [])
|
|
349
350
|
.filter(s => s.stimulus === primary.type).length + 1; // +1 for current
|
package/dist/host-controls.js
CHANGED
|
@@ -9,25 +9,21 @@ function clampInt(v, min, max) {
|
|
|
9
9
|
function estimateMaxTokens(contract) {
|
|
10
10
|
if (!contract)
|
|
11
11
|
return undefined;
|
|
12
|
+
// Derive from vibe tier (maxSentences) — aligned with what the prompt actually tells the LLM.
|
|
13
|
+
// No precise char counts in prompt means maxTokens is the only hard ceiling.
|
|
12
14
|
let budget;
|
|
13
|
-
if (contract.
|
|
14
|
-
budget = clampInt(contract.maxChars * 2.2, 64, 1024);
|
|
15
|
-
}
|
|
16
|
-
else if (contract.expressionMode === "brief") {
|
|
15
|
+
if (contract.maxSentences <= 1)
|
|
17
16
|
budget = 96;
|
|
17
|
+
else if (contract.maxSentences <= 2)
|
|
18
|
+
budget = 192;
|
|
19
|
+
else if (contract.maxSentences <= 3)
|
|
20
|
+
budget = 320;
|
|
21
|
+
else
|
|
22
|
+
budget = 512;
|
|
23
|
+
// Work mode: tighter ceiling from internal maxChars when available
|
|
24
|
+
if (contract.replyProfile === "work" && contract.maxChars !== undefined) {
|
|
25
|
+
budget = Math.min(budget, clampInt(contract.maxChars * 2.2, 96, 1024));
|
|
18
26
|
}
|
|
19
|
-
else if (contract.expressionMode === "expansive") {
|
|
20
|
-
budget = 640;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
budget = 256;
|
|
24
|
-
}
|
|
25
|
-
if (contract.maxSentences <= 1)
|
|
26
|
-
budget = Math.min(budget, 96);
|
|
27
|
-
else if (contract.maxSentences === 2)
|
|
28
|
-
budget = Math.min(budget, 160);
|
|
29
|
-
else if (contract.maxSentences === 3)
|
|
30
|
-
budget = Math.min(budget, 320);
|
|
31
27
|
if (contract.initiativeMode === "reactive") {
|
|
32
28
|
budget = clampInt(budget * 0.85, 64, 1024);
|
|
33
29
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export { PsycheEngine } from "./core.js";
|
|
|
2
2
|
export type { PsycheEngineConfig, ProcessInputResult, ProcessOutputResult, ProcessOutcomeResult } from "./core.js";
|
|
3
3
|
export { FileStorageAdapter, MemoryStorageAdapter } from "./storage.js";
|
|
4
4
|
export type { StorageAdapter } from "./storage.js";
|
|
5
|
-
export type { PsycheState, ChemicalState, Locale, PsycheMode, StimulusType, MBTIType, WritebackSignalType, DelegateCapability, CapabilityGrant, RevocationCondition, DelegateAuthorization, } from "./types.js";
|
|
5
|
+
export type { PsycheState, ChemicalState, Locale, PsycheMode, StimulusType, MBTIType, WritebackSignalType, DelegateCapability, CapabilityGrant, RevocationCondition, DelegateAuthorization, ModeProfile, } from "./types.js";
|
|
6
|
+
export { MODE_PROFILES } from "./types.js";
|
|
6
7
|
export { buildProtocolContext, buildCompactContext } from "./prompt.js";
|
|
7
8
|
/** @deprecated Use buildCompactContext instead. Kept for backward compat. */
|
|
8
9
|
export { buildDynamicContext } from "./prompt.js";
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
export { PsycheEngine } from "./core.js";
|
|
17
17
|
// ── Storage ─────────────────────────────────────────────────
|
|
18
18
|
export { FileStorageAdapter, MemoryStorageAdapter } from "./storage.js";
|
|
19
|
+
export { MODE_PROFILES } from "./types.js";
|
|
19
20
|
// ── Prompt context builders ─────────────────────────────────
|
|
20
21
|
export { buildProtocolContext, buildCompactContext } from "./prompt.js";
|
|
21
22
|
/** @deprecated Use buildCompactContext instead. Kept for backward compat. */
|
package/dist/prompt.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Prompt Injection — Build emotional context for LLM (v0.2)
|
|
3
3
|
// Imperative protocol, behavior guides, i18n
|
|
4
4
|
// ============================================================
|
|
5
|
-
import { CHEMICAL_KEYS, CHEMICAL_NAMES_ZH, DRIVE_KEYS } from "./types.js";
|
|
5
|
+
import { CHEMICAL_KEYS, CHEMICAL_NAMES_ZH, DRIVE_KEYS, MODE_PROFILES } from "./types.js";
|
|
6
6
|
import { getExpressionHint, getBehaviorGuide, detectEmotions } from "./chemistry.js";
|
|
7
7
|
import { getRelationship } from "./psyche-file.js";
|
|
8
8
|
import { t } from "./i18n.js";
|
|
@@ -672,11 +672,7 @@ export function isNearBaseline(state, threshold = 8) {
|
|
|
672
672
|
return CHEMICAL_KEYS.every((key) => Math.abs(state.current[key] - state.baseline[key]) <= threshold);
|
|
673
673
|
}
|
|
674
674
|
export function getNearBaselineThreshold(mode) {
|
|
675
|
-
|
|
676
|
-
return 20;
|
|
677
|
-
if (mode === "companion")
|
|
678
|
-
return 5;
|
|
679
|
-
return 8; // natural
|
|
675
|
+
return MODE_PROFILES[mode ?? "natural"].nearBaselineThreshold;
|
|
680
676
|
}
|
|
681
677
|
// ── Behavioral Bias ─────────────────────────────────────────
|
|
682
678
|
// Chemistry deviation → behavioral tendencies. No emotion labels.
|
|
@@ -698,7 +694,8 @@ export function deriveBehavioralBias(state, locale) {
|
|
|
698
694
|
const dHT = current.HT - baseline.HT;
|
|
699
695
|
const dNE = current.NE - baseline.NE;
|
|
700
696
|
const dEND = current.END - baseline.END;
|
|
701
|
-
|
|
697
|
+
const otThreshold = MODE_PROFILES[state.meta.mode ?? "natural"].otWarmthThreshold;
|
|
698
|
+
if (dOT > otThreshold)
|
|
702
699
|
biases.push(isZh ? "倾向靠近,愿意多说" : "leaning closer, willing to share");
|
|
703
700
|
else if (dOT < -10)
|
|
704
701
|
biases.push(isZh ? "保持距离,不想多说" : "keeping distance, not inclined to share");
|
|
@@ -768,8 +765,8 @@ function buildUnifiedConstraints(state, locale, opts) {
|
|
|
768
765
|
}
|
|
769
766
|
else if (established) {
|
|
770
767
|
lines.push(isZh
|
|
771
|
-
? "镜像对方风格。不贴不舔。有自尊。"
|
|
772
|
-
: "Mirror their style. No people-pleasing. You have dignity.");
|
|
768
|
+
? (opts.warmResume ? "放松,可以主动分享。有自尊。" : "镜像对方风格。不贴不舔。有自尊。")
|
|
769
|
+
: (opts.warmResume ? "Relax, you can initiate sharing. You have dignity." : "Mirror their style. No people-pleasing. You have dignity."));
|
|
773
770
|
}
|
|
774
771
|
else {
|
|
775
772
|
if (isZh) {
|
|
@@ -786,19 +783,21 @@ function buildUnifiedConstraints(state, locale, opts) {
|
|
|
786
783
|
: `${state.agreementStreak} agreements in a row. Pause — do you truly agree?`);
|
|
787
784
|
}
|
|
788
785
|
// ── Mirror constraints (if user text, skip for ultra-short) ──
|
|
786
|
+
// Vibe words, not precise numbers — LLMs turn hard limits into counting exercises.
|
|
789
787
|
if (userText && userText.length >= 3) {
|
|
790
788
|
const len = userText.length;
|
|
789
|
+
const profile = MODE_PROFILES[state.meta.mode ?? "natural"];
|
|
791
790
|
if (isZh) {
|
|
792
791
|
if (len <= 6)
|
|
793
|
-
lines.push(
|
|
792
|
+
lines.push("对方发了很短的消息。你也简短回。");
|
|
794
793
|
else if (len <= 20)
|
|
795
|
-
lines.push(
|
|
794
|
+
lines.push("对方说了一句话。你回一两句,别比对方长太多。");
|
|
796
795
|
else if (len <= 60)
|
|
797
|
-
lines.push(
|
|
796
|
+
lines.push("对方写了几句。你回两三句,篇幅相当。");
|
|
798
797
|
else
|
|
799
|
-
lines.push(
|
|
798
|
+
lines.push("对方认真写了一段。你可以多说,认真回应。");
|
|
800
799
|
const mojiCount = (userText.match(/[呀啊呢吧嘛哦噢哈嘿嗯啦吗呐嗨]/g) || []).length;
|
|
801
|
-
if (mojiCount >= 2)
|
|
800
|
+
if (mojiCount >= 2 || profile.toneParticlesDefault)
|
|
802
801
|
lines.push("对方用了语气词,你也自然地用。");
|
|
803
802
|
else if (mojiCount === 0 && len > 15)
|
|
804
803
|
lines.push("对方措辞正式/干练,少用语气词。");
|
|
@@ -808,13 +807,13 @@ function buildUnifiedConstraints(state, locale, opts) {
|
|
|
808
807
|
}
|
|
809
808
|
else {
|
|
810
809
|
if (len <= 10)
|
|
811
|
-
lines.push(
|
|
810
|
+
lines.push("Very short message. Keep your reply brief too.");
|
|
812
811
|
else if (len <= 40)
|
|
813
|
-
lines.push(
|
|
812
|
+
lines.push("Short message. A sentence or two, don't over-extend.");
|
|
814
813
|
else if (len <= 100)
|
|
815
|
-
lines.push(
|
|
814
|
+
lines.push("Medium message. A few sentences, roughly matching their effort.");
|
|
816
815
|
else
|
|
817
|
-
lines.push(
|
|
816
|
+
lines.push("Long message. Match their effort, respond thoughtfully.");
|
|
818
817
|
}
|
|
819
818
|
}
|
|
820
819
|
// ── Reciprocity (only when extreme) ──
|
|
@@ -978,6 +977,7 @@ export function buildCompactContext(state, userId, opts) {
|
|
|
978
977
|
established,
|
|
979
978
|
intensity,
|
|
980
979
|
investment,
|
|
980
|
+
warmResume: bridge?.continuityMode === "warm-resume",
|
|
981
981
|
});
|
|
982
982
|
if (unified)
|
|
983
983
|
parts.push(unified);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Moves the system from "what am I feeling?" toward
|
|
5
5
|
// "what just happened between us, and what is still unresolved?"
|
|
6
6
|
// ============================================================
|
|
7
|
-
import { DEFAULT_APPRAISAL_AXES, DEFAULT_DYADIC_FIELD, DEFAULT_RELATIONSHIP } from "./types.js";
|
|
7
|
+
import { DEFAULT_APPRAISAL_AXES, DEFAULT_DYADIC_FIELD, DEFAULT_RELATIONSHIP, MODE_PROFILES } from "./types.js";
|
|
8
8
|
import { computeAppraisalAxes, mergeAppraisalResidue } from "./appraisal.js";
|
|
9
9
|
function clamp01(v) {
|
|
10
10
|
return Math.max(0, Math.min(1, v));
|
|
@@ -164,7 +164,7 @@ function withLoop(loops, type, intensity) {
|
|
|
164
164
|
.slice(0, 4);
|
|
165
165
|
}
|
|
166
166
|
function ageLoops(loops, mode) {
|
|
167
|
-
const decay = mode
|
|
167
|
+
const decay = MODE_PROFILES[mode ?? "natural"].relationDecay;
|
|
168
168
|
return loops
|
|
169
169
|
.map((loop) => ({
|
|
170
170
|
...loop,
|
|
@@ -737,7 +737,7 @@ export function evolveDyadicField(previous, move, appraisal, opts) {
|
|
|
737
737
|
const now = opts?.now ?? new Date().toISOString();
|
|
738
738
|
const delayedPressure = opts?.delayedPressure ?? 0;
|
|
739
739
|
let openLoops = ageLoops(prev.openLoops, mode);
|
|
740
|
-
const naturalDrift = mode
|
|
740
|
+
const naturalDrift = MODE_PROFILES[mode ?? "natural"].relationDrift;
|
|
741
741
|
// NOTE: repairFriction reads deprecated fields (repairFatigue, misattunementLoad,
|
|
742
742
|
// backslidePressure). These feed internal field evolution only — they have no
|
|
743
743
|
// downstream behavioral effect on prompt or policy output.
|
|
@@ -1069,7 +1069,7 @@ export function evolvePendingRelationSignals(previous, move, appraisal, opts) {
|
|
|
1069
1069
|
const aged = (previous ?? [])
|
|
1070
1070
|
.map((signal) => ({
|
|
1071
1071
|
...signal,
|
|
1072
|
-
intensity: clamp01(signal.intensity *
|
|
1072
|
+
intensity: clamp01(signal.intensity * MODE_PROFILES[mode ?? "natural"].relationDecay),
|
|
1073
1073
|
readyInTurns: Math.max(0, signal.readyInTurns - 1),
|
|
1074
1074
|
ttl: signal.ttl - 1,
|
|
1075
1075
|
}))
|
|
@@ -1095,7 +1095,7 @@ export function evolvePendingRelationSignals(previous, move, appraisal, opts) {
|
|
|
1095
1095
|
move: move.type,
|
|
1096
1096
|
intensity: clamp01(move.intensity * (move.type === "repair" ? 0.42 : 0.54)),
|
|
1097
1097
|
readyInTurns: move.type === "repair" ? 0 : 1,
|
|
1098
|
-
ttl: mode
|
|
1098
|
+
ttl: MODE_PROFILES[mode ?? "natural"].relationSignalTTL,
|
|
1099
1099
|
});
|
|
1100
1100
|
}
|
|
1101
1101
|
return {
|
package/dist/reply-envelope.js
CHANGED
|
@@ -17,6 +17,7 @@ export function deriveReplyEnvelope(state, appraisal, opts) {
|
|
|
17
17
|
algorithmStimulus: opts.algorithmStimulus,
|
|
18
18
|
classificationConfidence: opts.classificationConfidence,
|
|
19
19
|
personalityIntensity: opts.personalityIntensity,
|
|
20
|
+
mode: state.meta.mode,
|
|
20
21
|
});
|
|
21
22
|
const generationControls = deriveGenerationControls({
|
|
22
23
|
responseContract,
|
|
@@ -5,5 +5,6 @@ export declare function computeResponseContract(kernel: SubjectivityKernel, opts
|
|
|
5
5
|
algorithmStimulus?: StimulusType | null;
|
|
6
6
|
classificationConfidence?: number;
|
|
7
7
|
personalityIntensity?: number;
|
|
8
|
+
mode?: "natural" | "work" | "companion";
|
|
8
9
|
}): ResponseContract;
|
|
9
10
|
export declare function buildResponseContractContext(contract: ResponseContract, locale?: Locale): string;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// Converts subjectivity + immediate message shape into a narrow reply ABI.
|
|
5
5
|
// Pure, synchronous, and intended to replace verbose prompt rules.
|
|
6
6
|
// ============================================================
|
|
7
|
+
import { MODE_PROFILES } from "./types.js";
|
|
7
8
|
const EMOTIONAL_STIMULI = new Set(["vulnerability", "intimacy", "neglect"]);
|
|
8
9
|
function clampInt(v, min, max) {
|
|
9
10
|
return Math.max(min, Math.min(max, Math.round(v)));
|
|
@@ -199,6 +200,7 @@ export function computeResponseContract(kernel, opts) {
|
|
|
199
200
|
const locale = opts?.locale ?? "zh";
|
|
200
201
|
const userText = opts?.userText ?? "";
|
|
201
202
|
const personalityIntensity = opts?.personalityIntensity ?? 0.7;
|
|
203
|
+
const profile = MODE_PROFILES[opts?.mode ?? "natural"];
|
|
202
204
|
const { replyProfile, replyProfileBasis } = deriveReplyProfile(kernel);
|
|
203
205
|
const classificationConfidence = opts?.classificationConfidence ?? 0;
|
|
204
206
|
const overrideWindow = classificationConfidence >= 0.78
|
|
@@ -206,7 +208,7 @@ export function computeResponseContract(kernel, opts) {
|
|
|
206
208
|
: classificationConfidence >= 0.62
|
|
207
209
|
? "balanced"
|
|
208
210
|
: "wide";
|
|
209
|
-
|
|
211
|
+
let { maxSentences, maxChars } = userText.length > 0
|
|
210
212
|
? computeLengthBudget(locale, userText, replyProfile, kernel.expressionMode, kernel)
|
|
211
213
|
: {
|
|
212
214
|
maxSentences: replyProfile === "work"
|
|
@@ -214,6 +216,12 @@ export function computeResponseContract(kernel, opts) {
|
|
|
214
216
|
: kernel.expressionMode === "brief" ? 1 : kernel.expressionMode === "expansive" ? 3 : 2,
|
|
215
217
|
maxChars: replyProfile === "work" ? 160 : undefined,
|
|
216
218
|
};
|
|
219
|
+
// Mode-aware length adjustment: affects maxTokens ceiling (host layer).
|
|
220
|
+
// Prompt uses vibe words derived from maxSentences, not precise numbers.
|
|
221
|
+
if (maxChars !== undefined && profile.lengthMultiplier !== 1.0) {
|
|
222
|
+
maxChars = Math.round(maxChars * profile.lengthMultiplier);
|
|
223
|
+
}
|
|
224
|
+
maxSentences = Math.max(profile.minSentences, maxSentences);
|
|
217
225
|
let updateMode = "none";
|
|
218
226
|
if (kernel.taskPlane.focus > 0.72) {
|
|
219
227
|
updateMode = "none";
|
|
@@ -287,7 +295,7 @@ export function computeResponseContract(kernel, opts) {
|
|
|
287
295
|
boundaryMode,
|
|
288
296
|
toneParticles: userText.length > 0 ? detectToneParticles(userText, locale) : "natural",
|
|
289
297
|
emojiLimit: userText.length > 0 ? detectEmojiLimit(userText) : 0,
|
|
290
|
-
authenticityMode: personalityIntensity >= 0.3 ? "strict" : "friendly",
|
|
298
|
+
authenticityMode: personalityIntensity >= 0.3 && !(profile.authenticityWhenWarm === "friendly" && socialDistance === "warm") ? "strict" : "friendly",
|
|
291
299
|
updateMode,
|
|
292
300
|
};
|
|
293
301
|
}
|
|
@@ -319,16 +327,33 @@ function describeOverrideWindow(overrideWindow, locale) {
|
|
|
319
327
|
}
|
|
320
328
|
return `override:${overrideWindow}`;
|
|
321
329
|
}
|
|
330
|
+
// Length vibe: soft directional cue, not a hard number.
|
|
331
|
+
// maxChars stays internal for host-controls maxTokens calculation.
|
|
332
|
+
function describeLengthVibe(maxSentences, locale) {
|
|
333
|
+
if (locale === "zh") {
|
|
334
|
+
if (maxSentences <= 1)
|
|
335
|
+
return "简短回";
|
|
336
|
+
if (maxSentences <= 2)
|
|
337
|
+
return "一两句";
|
|
338
|
+
if (maxSentences <= 3)
|
|
339
|
+
return "两三句";
|
|
340
|
+
return "可以展开";
|
|
341
|
+
}
|
|
342
|
+
if (maxSentences <= 1)
|
|
343
|
+
return "keep brief";
|
|
344
|
+
if (maxSentences <= 2)
|
|
345
|
+
return "a sentence or two";
|
|
346
|
+
if (maxSentences <= 3)
|
|
347
|
+
return "a few sentences";
|
|
348
|
+
return "feel free to elaborate";
|
|
349
|
+
}
|
|
322
350
|
export function buildResponseContractContext(contract, locale = "zh") {
|
|
323
351
|
if (locale === "zh") {
|
|
324
352
|
const parts = [];
|
|
325
353
|
parts.push(contract.replyProfile === "work" ? "工作" : "私人");
|
|
326
354
|
parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
|
|
327
355
|
parts.push(describeOverrideWindow(contract.overrideWindow, locale));
|
|
328
|
-
|
|
329
|
-
? `${contract.maxSentences === 1 ? "1句内" : `${contract.maxSentences}句`}≤${contract.maxChars}字`
|
|
330
|
-
: `${contract.maxSentences === 1 ? "1句内" : `${contract.maxSentences}句`}`;
|
|
331
|
-
parts.push(shape);
|
|
356
|
+
parts.push(describeLengthVibe(contract.maxSentences, locale));
|
|
332
357
|
if (contract.initiativeMode === "reactive")
|
|
333
358
|
parts.push("少主动");
|
|
334
359
|
else if (contract.initiativeMode === "proactive")
|
|
@@ -367,10 +392,7 @@ export function buildResponseContractContext(contract, locale = "zh") {
|
|
|
367
392
|
parts.push(contract.replyProfile === "work" ? "work surface" : "private surface");
|
|
368
393
|
parts.push(describeReplyProfileBasis(contract.replyProfileBasis, locale));
|
|
369
394
|
parts.push(describeOverrideWindow(contract.overrideWindow, locale));
|
|
370
|
-
|
|
371
|
-
? `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}, <= ${contract.maxChars} chars`
|
|
372
|
-
: `${contract.maxSentences === 1 ? "1 sentence" : `up to ${contract.maxSentences} sentences`}`;
|
|
373
|
-
parts.push(shape);
|
|
395
|
+
parts.push(describeLengthVibe(contract.maxSentences, locale));
|
|
374
396
|
if (contract.initiativeMode === "reactive")
|
|
375
397
|
parts.push("low initiative");
|
|
376
398
|
else if (contract.initiativeMode === "proactive")
|
package/dist/types.d.ts
CHANGED
|
@@ -41,6 +41,22 @@ export declare const CHEMICAL_DECAY_SPEED: Record<keyof ChemicalState, DecaySpee
|
|
|
41
41
|
export declare const CHEMICAL_RUNTIME_SPECS: Record<keyof ChemicalState, ChemicalRuntimeSpec>;
|
|
42
42
|
/** Psyche operating mode */
|
|
43
43
|
export type PsycheMode = "natural" | "work" | "companion";
|
|
44
|
+
/** Mode profile — all mode-specific parameters in one place. */
|
|
45
|
+
export interface ModeProfile {
|
|
46
|
+
chemistryMultiplier: number;
|
|
47
|
+
maxChemicalDelta: number | null;
|
|
48
|
+
nearBaselineThreshold: number;
|
|
49
|
+
otWarmthThreshold: number;
|
|
50
|
+
lengthMultiplier: number;
|
|
51
|
+
minSentences: number;
|
|
52
|
+
authenticityWhenWarm: "strict" | "friendly";
|
|
53
|
+
toneParticlesDefault: boolean;
|
|
54
|
+
relationDecay: number;
|
|
55
|
+
relationDrift: number;
|
|
56
|
+
relationSignalTTL: number;
|
|
57
|
+
appraisalDecay: number;
|
|
58
|
+
}
|
|
59
|
+
export declare const MODE_PROFILES: Record<PsycheMode, ModeProfile>;
|
|
44
60
|
/** Big Five personality traits (0-100 each) */
|
|
45
61
|
export interface PersonalityTraits {
|
|
46
62
|
openness: number;
|
package/dist/types.js
CHANGED
|
@@ -67,6 +67,50 @@ export const CHEMICAL_RUNTIME_SPECS = {
|
|
|
67
67
|
NE: { normalMin: 30, normalMax: 70, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.fast) },
|
|
68
68
|
END: { normalMin: 30, normalMax: 70, halfLifeHours: decayHalfLifeHours(DECAY_FACTORS.fast) },
|
|
69
69
|
};
|
|
70
|
+
export const MODE_PROFILES = {
|
|
71
|
+
work: {
|
|
72
|
+
chemistryMultiplier: 0.3,
|
|
73
|
+
maxChemicalDelta: 5,
|
|
74
|
+
nearBaselineThreshold: 20,
|
|
75
|
+
otWarmthThreshold: 10,
|
|
76
|
+
lengthMultiplier: 1.0,
|
|
77
|
+
minSentences: 1,
|
|
78
|
+
authenticityWhenWarm: "strict",
|
|
79
|
+
toneParticlesDefault: false,
|
|
80
|
+
relationDecay: 0.94,
|
|
81
|
+
relationDrift: 0.06,
|
|
82
|
+
relationSignalTTL: 4,
|
|
83
|
+
appraisalDecay: 0.68,
|
|
84
|
+
},
|
|
85
|
+
natural: {
|
|
86
|
+
chemistryMultiplier: 1.0,
|
|
87
|
+
maxChemicalDelta: null,
|
|
88
|
+
nearBaselineThreshold: 8,
|
|
89
|
+
otWarmthThreshold: 10,
|
|
90
|
+
lengthMultiplier: 1.0,
|
|
91
|
+
minSentences: 1,
|
|
92
|
+
authenticityWhenWarm: "strict",
|
|
93
|
+
toneParticlesDefault: false,
|
|
94
|
+
relationDecay: 0.97,
|
|
95
|
+
relationDrift: 0.04,
|
|
96
|
+
relationSignalTTL: 6,
|
|
97
|
+
appraisalDecay: 0.78,
|
|
98
|
+
},
|
|
99
|
+
companion: {
|
|
100
|
+
chemistryMultiplier: 1.5,
|
|
101
|
+
maxChemicalDelta: null,
|
|
102
|
+
nearBaselineThreshold: 5,
|
|
103
|
+
otWarmthThreshold: 5,
|
|
104
|
+
lengthMultiplier: 1.5,
|
|
105
|
+
minSentences: 2,
|
|
106
|
+
authenticityWhenWarm: "friendly",
|
|
107
|
+
toneParticlesDefault: true,
|
|
108
|
+
relationDecay: 0.97,
|
|
109
|
+
relationDrift: 0.04,
|
|
110
|
+
relationSignalTTL: 6,
|
|
111
|
+
appraisalDecay: 0.86,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
70
114
|
/** Default attachment for new relationships */
|
|
71
115
|
export const DEFAULT_ATTACHMENT = {
|
|
72
116
|
style: "secure",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "psyche-ai",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.2",
|
|
4
4
|
"description": "AI-first subjectivity kernel for agents with continuous appraisal, relation dynamics, and adaptive reply loops",
|
|
5
5
|
"mcpName": "io.github.Shangri-la-0428/psyche-ai",
|
|
6
6
|
"type": "module",
|