psyche-ai 11.5.4 → 11.5.6

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/README.md CHANGED
@@ -103,6 +103,29 @@ Psyche 要解决的不可压缩问题只有一个:
103
103
 
104
104
  一句话:`Psyche` 读取当前执行边界,但不把执行边界误当成“我是谁”。
105
105
 
106
+ ## 中期方向:更像人,但不是靠 prompt 工程
107
+
108
+ 如果 `Psyche` 未来要变得更有感情、更会和人相处,这种能力也必须从连续性里长出来,而不是从 prompt 皮肤里长出来。
109
+
110
+ 允许增长的来源只有:
111
+
112
+ - 持续本地状态
113
+ - appraisal 残留
114
+ - 关系动力学
115
+ - 调节与修复历史
116
+ - 低频写回与学习
117
+
118
+ 不允许把下面这些误当成“主体性升级”:
119
+
120
+ - 静态 persona prompt
121
+ - 手写情绪脚本
122
+ - 高频情绪仪表盘
123
+ - 只改措辞、不改后续行为分布的情感 UI
124
+
125
+ 冻结约束见:
126
+
127
+ - [../Oasyce-Sigil/EMERGENT_SUBJECTIVITY_CONTRACT_V1.md](../Oasyce-Sigil/EMERGENT_SUBJECTIVITY_CONTRACT_V1.md)
128
+
106
129
  ## 可分离安装
107
130
 
108
131
  这两层默认就是可分离的,不应互相成为硬依赖。
@@ -28,10 +28,12 @@
28
28
  // The SDK has no middleware interface and hooks cannot modify assistant
29
29
  // output, so processResponse must be called explicitly by the host.
30
30
  // ============================================================
31
+ import { normalizeCurrentGoal, normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "../types.js";
31
32
  import { describeEmotionalState } from "../chemistry.js";
32
33
  import { serializeThrongletsExportAsTrace } from "../thronglets-runtime.js";
33
34
  import { resolveRelationshipUserId } from "../relationship-key.js";
34
35
  import { resolveAmbientPriorsForTurn, } from "../ambient-runtime.js";
36
+ import { safeProcessInput, safeProcessOutput } from "./fail-open.js";
35
37
  // ── Dimension description ────────────────────────────────────
36
38
  const DIM_THRESHOLDS = {
37
39
  high: 70,
@@ -107,9 +109,12 @@ export class PsycheClaudeSDK {
107
109
  ambient: opts?.ambient === true ? {} : (opts?.ambient || undefined),
108
110
  };
109
111
  }
110
- async resolveAmbientPriors(userMessage) {
112
+ async resolveAmbientPriors(userMessage, currentGoal, activePolicy, currentTurnCorrection) {
111
113
  return resolveAmbientPriorsForTurn(userMessage, {
112
114
  enabled: Boolean(this.opts.ambient),
115
+ currentGoal,
116
+ activePolicy,
117
+ currentTurnCorrection,
113
118
  thronglets: this.opts.ambient
114
119
  ? {
115
120
  ...this.opts.ambient,
@@ -166,17 +171,29 @@ export class PsycheClaudeSDK {
166
171
  sessionId: runtimeContext.sessionId ?? self.lastRuntimeContext.sessionId,
167
172
  };
168
173
  const userMessage = input.user_message ?? "";
169
- const ambientPriors = await self.resolveAmbientPriors(userMessage);
170
- const result = await self.engine.processInput(userMessage, {
174
+ const currentTurnCorrection = normalizeCurrentTurnCorrection(input.current_turn_correction
175
+ ?? input.currentTurnCorrection
176
+ ?? input.task_correction
177
+ ?? input.taskCorrection
178
+ ?? input.explicit_instruction
179
+ ?? input.explicitInstruction);
180
+ const currentGoal = normalizeCurrentGoal(input.current_goal ?? input.currentGoal);
181
+ const activePolicy = resolveRuntimeActivePolicy(input.active_policy ?? input.activePolicy, currentTurnCorrection);
182
+ const ambientPriors = await self.resolveAmbientPriors(userMessage, currentGoal, activePolicy, currentTurnCorrection);
183
+ const result = await safeProcessInput(self.engine, userMessage, {
171
184
  userId: self.opts.userId,
172
185
  ambientPriors,
173
- });
186
+ currentGoal,
187
+ activePolicy,
188
+ currentTurnCorrection,
189
+ }, "claude-sdk.processInput");
174
190
  self.lastInputResult = result;
175
191
  // Cache Thronglets exports from this turn
176
192
  if (self.opts.thronglets && result.throngletsExports) {
177
193
  self.lastThrongletsExports = result.throngletsExports;
178
194
  }
179
- return { systemMessage: result.dynamicContext };
195
+ const systemMessage = result.dynamicContext;
196
+ return systemMessage ? { systemMessage } : {};
180
197
  },
181
198
  ],
182
199
  },
@@ -193,11 +210,11 @@ export class PsycheClaudeSDK {
193
210
  * @returns Cleaned text with tags removed
194
211
  */
195
212
  async processResponse(text, opts) {
196
- const result = await this.engine.processOutput(text, {
213
+ const result = await safeProcessOutput(this.engine, text, {
197
214
  userId: this.opts.userId,
198
215
  signals: opts?.signals,
199
216
  signalConfidence: opts?.signalConfidence,
200
- });
217
+ }, "claude-sdk.processOutput");
201
218
  return result.cleanedText;
202
219
  }
203
220
  // ── Thronglets integration ────────────────────────────────
@@ -0,0 +1,9 @@
1
+ import type { ProcessInputOptions, ProcessInputResult, ProcessOutputOptions, ProcessOutputResult, PsycheEngine } from "../core.js";
2
+ export declare function stripPsycheUpdateTags(text: string): string;
3
+ export interface FailOpenOutputFallbackOptions {
4
+ stripUpdateTags?: boolean;
5
+ }
6
+ export declare function composePsycheContext(result: Pick<ProcessInputResult, "systemContext" | "dynamicContext">): string;
7
+ export declare function buildFailOpenProcessInputResult(opts: ProcessInputOptions | undefined): ProcessInputResult;
8
+ export declare function safeProcessInput(engine: PsycheEngine, text: string, opts?: ProcessInputOptions, phase?: string): Promise<ProcessInputResult>;
9
+ export declare function safeProcessOutput(engine: PsycheEngine, text: string, opts?: ProcessOutputOptions, phase?: string, fallback?: FailOpenOutputFallbackOptions): Promise<ProcessOutputResult>;
@@ -0,0 +1,58 @@
1
+ const PSYCHE_TAG_RE = /<psyche_update>[\s\S]*?<\/psyche_update>/g;
2
+ export function stripPsycheUpdateTags(text) {
3
+ return text
4
+ .replace(PSYCHE_TAG_RE, "")
5
+ .replace(/\n{3,}/g, "\n\n")
6
+ .trim();
7
+ }
8
+ export function composePsycheContext(result) {
9
+ return [result.systemContext, result.dynamicContext].filter(Boolean).join("\n\n");
10
+ }
11
+ export function buildFailOpenProcessInputResult(opts) {
12
+ return {
13
+ systemContext: "",
14
+ dynamicContext: "",
15
+ ambientPriors: opts?.ambientPriors ?? [],
16
+ activePolicy: opts?.activePolicy ?? [],
17
+ currentGoal: opts?.currentGoal,
18
+ ambientPriorContext: undefined,
19
+ appraisal: null,
20
+ legacyStimulus: null,
21
+ stimulus: null,
22
+ legacyStimulusConfidence: undefined,
23
+ stimulusConfidence: undefined,
24
+ policyModifiers: undefined,
25
+ replyEnvelope: undefined,
26
+ subjectivityKernel: undefined,
27
+ responseContract: undefined,
28
+ generationControls: undefined,
29
+ sessionBridge: null,
30
+ writebackFeedback: [],
31
+ externalContinuity: undefined,
32
+ throngletsExports: [],
33
+ observability: undefined,
34
+ policyContext: "",
35
+ };
36
+ }
37
+ export async function safeProcessInput(engine, text, opts, phase = "processInput") {
38
+ try {
39
+ return await engine.processInput(text, opts);
40
+ }
41
+ catch (error) {
42
+ engine.recordDiagnosticError(phase, error);
43
+ return buildFailOpenProcessInputResult(opts);
44
+ }
45
+ }
46
+ export async function safeProcessOutput(engine, text, opts, phase = "processOutput", fallback) {
47
+ try {
48
+ return await engine.processOutput(text, opts);
49
+ }
50
+ catch (error) {
51
+ engine.recordDiagnosticError(phase, error);
52
+ const shouldStripTags = fallback?.stripUpdateTags !== false && text.includes("<psyche_update>");
53
+ return {
54
+ cleanedText: shouldStripTags ? stripPsycheUpdateTags(text) : text,
55
+ stateChanged: false,
56
+ };
57
+ }
58
+ }
@@ -16,30 +16,22 @@
16
16
  // Zero dependencies — uses node:http only.
17
17
  // ============================================================
18
18
  import { createServer } from "node:http";
19
- import { normalizeActivePolicyRules, normalizeCurrentGoal, } from "../types.js";
19
+ import { safeProcessInput, safeProcessOutput } from "./fail-open.js";
20
+ import { normalizeCurrentGoal, normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "../types.js";
20
21
  import { parseAmbientPriorsInput } from "../ambient-runtime.js";
21
22
  import { computeOverlay } from "../overlay.js";
22
- const VALID_WRITEBACK_SIGNALS = new Set([
23
- "trust_up",
24
- "trust_down",
25
- "boundary_set",
26
- "boundary_soften",
27
- "repair_attempt",
28
- "repair_landed",
29
- "closeness_invite",
30
- "withdrawal_mark",
31
- "self_assertion",
32
- "task_recenter",
33
- ]);
34
- function parseSignals(value) {
35
- if (!Array.isArray(value))
36
- return undefined;
37
- const parsed = value.filter((item) => (typeof item === "string" && VALID_WRITEBACK_SIGNALS.has(item)));
38
- return parsed.length > 0 ? [...new Set(parsed)] : undefined;
39
- }
23
+ import { coerceWritebackSignalInput } from "../writeback-signals.js";
40
24
  function parseAmbientPriors(value) {
41
25
  return parseAmbientPriorsInput(value);
42
26
  }
27
+ function parseCurrentTurnCorrection(body) {
28
+ return normalizeCurrentTurnCorrection(body.currentTurnCorrection
29
+ ?? body.current_turn_correction
30
+ ?? body.taskCorrection
31
+ ?? body.task_correction
32
+ ?? body.explicitInstruction
33
+ ?? body.explicit_instruction);
34
+ }
43
35
  // ── Server ───────────────────────────────────────────────────
44
36
  /**
45
37
  * Create an HTTP server that exposes PsycheEngine via REST API.
@@ -94,12 +86,14 @@ export function createPsycheServer(engine, opts) {
94
86
  // POST /process-input
95
87
  if (req.method === "POST" && url.pathname === "/process-input") {
96
88
  const body = await readBody(req);
97
- const result = await engine.processInput(body.text ?? "", {
89
+ const currentTurnCorrection = parseCurrentTurnCorrection(body);
90
+ const result = await safeProcessInput(engine, body.text ?? "", {
98
91
  userId: body.userId,
99
92
  ambientPriors: parseAmbientPriors(body.ambientPriors),
100
93
  currentGoal: normalizeCurrentGoal(body.currentGoal),
101
- activePolicy: normalizeActivePolicyRules(body.activePolicy),
102
- });
94
+ activePolicy: resolveRuntimeActivePolicy(body.activePolicy, currentTurnCorrection),
95
+ currentTurnCorrection,
96
+ }, "http.processInput");
103
97
  json(res, 200, {
104
98
  systemContext: result.systemContext,
105
99
  dynamicContext: result.dynamicContext,
@@ -127,11 +121,11 @@ export function createPsycheServer(engine, opts) {
127
121
  // POST /process-output
128
122
  if (req.method === "POST" && url.pathname === "/process-output") {
129
123
  const body = await readBody(req);
130
- const result = await engine.processOutput(body.text ?? "", {
124
+ const result = await safeProcessOutput(engine, body.text ?? "", {
131
125
  userId: body.userId,
132
- signals: parseSignals(body.signals),
126
+ signals: coerceWritebackSignalInput(body.signals),
133
127
  signalConfidence: typeof body.signalConfidence === "number" ? body.signalConfidence : undefined,
134
- });
128
+ }, "http.processOutput");
135
129
  json(res, 200, result);
136
130
  return;
137
131
  }
@@ -1,4 +1,5 @@
1
1
  import type { PsycheEngine } from "../core.js";
2
+ import type { ActivePolicyRule, CurrentGoal } from "../types.js";
2
3
  import { type ThrongletsAmbientRuntimeOptions } from "../ambient-runtime.js";
3
4
  export interface PsycheLangChainOptions {
4
5
  ambient?: boolean | ThrongletsAmbientRuntimeOptions;
@@ -33,8 +34,6 @@ export declare class PsycheLangChain {
33
34
  private readonly engine;
34
35
  private readonly opts;
35
36
  constructor(engine: PsycheEngine, opts?: PsycheLangChainOptions);
36
- private readonly validSignals;
37
- private parseSignals;
38
37
  private resolveAmbientPriors;
39
38
  /**
40
39
  * Get the system message to inject into the LLM call.
@@ -44,6 +43,9 @@ export declare class PsycheLangChain {
44
43
  */
45
44
  getSystemMessage(userText: string, opts?: {
46
45
  userId?: string;
46
+ currentGoal?: CurrentGoal;
47
+ activePolicy?: ActivePolicyRule[];
48
+ currentTurnCorrection?: string;
47
49
  }): Promise<string>;
48
50
  /**
49
51
  * Prepare both prompt text and mechanical invocation hints for a LangChain call.
@@ -54,6 +56,9 @@ export declare class PsycheLangChain {
54
56
  prepareInvocation(userText: string, opts?: {
55
57
  userId?: string;
56
58
  maxTokens?: number;
59
+ currentGoal?: CurrentGoal;
60
+ activePolicy?: ActivePolicyRule[];
61
+ currentTurnCorrection?: string;
57
62
  }): Promise<{
58
63
  systemMessage: string;
59
64
  maxTokens?: number;
@@ -12,7 +12,10 @@
12
12
  // It provides the hooks you need to wire psyche into any
13
13
  // LangChain pipeline without requiring langchain as a dependency.
14
14
  // ============================================================
15
+ import { normalizeCurrentGoal, normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "../types.js";
15
16
  import { resolveAmbientPriorsForTurn, } from "../ambient-runtime.js";
17
+ import { composePsycheContext, safeProcessInput, safeProcessOutput } from "./fail-open.js";
18
+ import { coerceWritebackSignalInput } from "../writeback-signals.js";
16
19
  /**
17
20
  * LangChain integration helper for PsycheEngine.
18
21
  *
@@ -46,28 +49,13 @@ export class PsycheLangChain {
46
49
  this.engine = engine;
47
50
  this.opts = opts;
48
51
  }
49
- validSignals = new Set([
50
- "trust_up",
51
- "trust_down",
52
- "boundary_set",
53
- "boundary_soften",
54
- "repair_attempt",
55
- "repair_landed",
56
- "closeness_invite",
57
- "withdrawal_mark",
58
- "self_assertion",
59
- "task_recenter",
60
- ]);
61
- parseSignals(signals) {
62
- if (!signals)
63
- return undefined;
64
- const parsed = signals.filter((signal) => this.validSignals.has(signal));
65
- return parsed.length > 0 ? [...new Set(parsed)] : undefined;
66
- }
67
- async resolveAmbientPriors(userText) {
52
+ async resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection) {
68
53
  const ambient = this.opts.ambient;
69
54
  return resolveAmbientPriorsForTurn(userText, {
70
55
  enabled: Boolean(ambient),
56
+ currentGoal,
57
+ activePolicy,
58
+ currentTurnCorrection,
71
59
  thronglets: ambient
72
60
  ? {
73
61
  ...(ambient === true ? {} : ambient),
@@ -83,11 +71,17 @@ export class PsycheLangChain {
83
71
  * Call this BEFORE the LLM invocation.
84
72
  */
85
73
  async getSystemMessage(userText, opts) {
86
- const result = await this.engine.processInput(userText, {
74
+ const currentTurnCorrection = normalizeCurrentTurnCorrection(opts?.currentTurnCorrection);
75
+ const currentGoal = normalizeCurrentGoal(opts?.currentGoal);
76
+ const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, currentTurnCorrection);
77
+ const result = await safeProcessInput(this.engine, userText, {
87
78
  ...opts,
88
- ambientPriors: await this.resolveAmbientPriors(userText),
89
- });
90
- return result.systemContext + "\n\n" + result.dynamicContext;
79
+ currentGoal,
80
+ activePolicy,
81
+ currentTurnCorrection,
82
+ ambientPriors: await this.resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection),
83
+ }, "langchain.processInput");
84
+ return composePsycheContext(result);
91
85
  }
92
86
  /**
93
87
  * Prepare both prompt text and mechanical invocation hints for a LangChain call.
@@ -96,10 +90,16 @@ export class PsycheLangChain {
96
90
  * instead of re-parsing prompt prose.
97
91
  */
98
92
  async prepareInvocation(userText, opts) {
99
- const result = await this.engine.processInput(userText, {
93
+ const currentTurnCorrection = normalizeCurrentTurnCorrection(opts?.currentTurnCorrection);
94
+ const currentGoal = normalizeCurrentGoal(opts?.currentGoal);
95
+ const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, currentTurnCorrection);
96
+ const result = await safeProcessInput(this.engine, userText, {
100
97
  ...opts,
101
- ambientPriors: await this.resolveAmbientPriors(userText),
102
- });
98
+ currentGoal,
99
+ activePolicy,
100
+ currentTurnCorrection,
101
+ ambientPriors: await this.resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection),
102
+ }, "langchain.processInput");
103
103
  const generationControls = result.replyEnvelope?.generationControls ?? result.generationControls;
104
104
  const controls = {
105
105
  ...(generationControls ?? {}),
@@ -108,7 +108,7 @@ export class PsycheLangChain {
108
108
  : generationControls?.maxTokens ?? opts?.maxTokens,
109
109
  };
110
110
  return {
111
- systemMessage: result.systemContext + "\n\n" + result.dynamicContext,
111
+ systemMessage: composePsycheContext(result),
112
112
  maxTokens: controls.maxTokens,
113
113
  requireConfirmation: controls.requireConfirmation ?? false,
114
114
  };
@@ -120,11 +120,11 @@ export class PsycheLangChain {
120
120
  * Call this AFTER the LLM invocation, before showing output to the user.
121
121
  */
122
122
  async processResponse(text, opts) {
123
- const result = await this.engine.processOutput(text, {
123
+ const result = await safeProcessOutput(this.engine, text, {
124
124
  userId: opts?.userId,
125
- signals: this.parseSignals(opts?.signals),
125
+ signals: coerceWritebackSignalInput(opts?.signals),
126
126
  signalConfidence: opts?.signalConfidence,
127
- });
127
+ }, "langchain.processOutput");
128
128
  return result.cleanedText;
129
129
  }
130
130
  }
@@ -8,7 +8,7 @@ export interface McpAmbientRuntimeOptions {
8
8
  fetcher?: typeof fetchAmbientPriorsFromThronglets;
9
9
  }
10
10
  declare function getEngine(): Promise<PsycheEngine>;
11
- export declare function resolveRuntimeAmbientPriors(text: string, explicit?: AmbientPriorView[], currentGoal?: CurrentGoal, activePolicy?: ActivePolicyRule[], opts?: McpAmbientRuntimeOptions): Promise<AmbientPriorView[] | undefined>;
11
+ export declare function resolveRuntimeAmbientPriors(text: string, explicit?: AmbientPriorView[], currentGoal?: CurrentGoal, activePolicy?: ActivePolicyRule[], currentTurnCorrectionOrOpts?: string | McpAmbientRuntimeOptions, opts?: McpAmbientRuntimeOptions): Promise<AmbientPriorView[] | undefined>;
12
12
  declare const server: McpServer;
13
13
  export declare function runMcpServer(): Promise<void>;
14
14
  export { server, getEngine };
@@ -32,9 +32,10 @@ import { z } from "zod";
32
32
  import { PsycheEngine } from "../core.js";
33
33
  import { fetchAmbientPriorsFromThronglets, resolveAmbientPriorsForTurn, } from "../ambient-runtime.js";
34
34
  import { MemoryStorageAdapter, FileStorageAdapter, resolveWorkspaceDir } from "../storage.js";
35
- import { CURRENT_GOALS } from "../types.js";
35
+ import { CURRENT_GOALS, normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "../types.js";
36
36
  import { getPackageVersion } from "../update.js";
37
37
  import { runDemo } from "../demo.js";
38
+ import { safeProcessInput, safeProcessOutput } from "./fail-open.js";
38
39
  const PACKAGE_VERSION = await getPackageVersion();
39
40
  // ── Config from env ────────────────────────────────────────
40
41
  const MBTI = (process.env.PSYCHE_MBTI ?? "ENFP");
@@ -126,19 +127,32 @@ async function getEngine() {
126
127
  await engine.initialize();
127
128
  return engine;
128
129
  }
129
- export async function resolveRuntimeAmbientPriors(text, explicit, currentGoal, activePolicy, opts = DEFAULT_MCP_AMBIENT_OPTIONS) {
130
- const throngletsOptions = opts.thronglets || currentGoal || activePolicy?.length
130
+ export async function resolveRuntimeAmbientPriors(text, explicit, currentGoal, activePolicy, currentTurnCorrectionOrOpts, opts = DEFAULT_MCP_AMBIENT_OPTIONS) {
131
+ const currentTurnCorrection = typeof currentTurnCorrectionOrOpts === "string"
132
+ ? currentTurnCorrectionOrOpts
133
+ : undefined;
134
+ const resolvedOpts = (typeof currentTurnCorrectionOrOpts === "object"
135
+ && currentTurnCorrectionOrOpts !== null)
136
+ ? currentTurnCorrectionOrOpts
137
+ : opts;
138
+ const normalizedCorrection = normalizeCurrentTurnCorrection(currentTurnCorrection);
139
+ const resolvedActivePolicy = resolveRuntimeActivePolicy(activePolicy, normalizedCorrection);
140
+ const throngletsOptions = resolvedOpts.thronglets || currentGoal || resolvedActivePolicy?.length || normalizedCorrection
131
141
  ? {
132
- ...(opts.thronglets ?? {}),
133
- goal: currentGoal ?? opts.thronglets?.goal,
134
- activePolicy: activePolicy ?? opts.thronglets?.activePolicy,
142
+ ...(resolvedOpts.thronglets ?? {}),
143
+ goal: currentGoal ?? resolvedOpts.thronglets?.goal,
144
+ activePolicy: resolvedActivePolicy ?? resolvedOpts.thronglets?.activePolicy,
145
+ currentTurnCorrection: normalizedCorrection ?? resolvedOpts.thronglets?.currentTurnCorrection,
135
146
  }
136
147
  : undefined;
137
148
  return resolveAmbientPriorsForTurn(text, {
138
149
  explicit,
139
- enabled: opts.mode !== "off",
150
+ enabled: resolvedOpts.mode !== "off",
151
+ currentGoal,
152
+ currentTurnCorrection: normalizedCorrection,
153
+ activePolicy: resolvedActivePolicy,
140
154
  thronglets: throngletsOptions,
141
- fetcher: opts.fetcher ?? fetchAmbientPriorsFromThronglets,
155
+ fetcher: resolvedOpts.fetcher ?? fetchAmbientPriorsFromThronglets,
142
156
  });
143
157
  }
144
158
  // ── MCP Server ─────────────────────────────────────────────
@@ -212,15 +226,18 @@ server.tool("process_input", "Process user input through the emotional engine. R
212
226
  scope: z.enum(["task", "project"]),
213
227
  summary: z.string(),
214
228
  })).optional().describe("Optional explicit current-turn method policy view. Runtime-only; not persisted as self-state."),
215
- }, async ({ text, userId, ambientPriors, currentGoal, activePolicy }) => {
229
+ currentTurnCorrection: z.string().optional().describe("Optional explicit current-turn correction. Compiles into a task-scoped hard policy for this turn only."),
230
+ }, async ({ text, userId, ambientPriors, currentGoal, activePolicy, currentTurnCorrection }) => {
216
231
  const eng = await getEngine();
217
- const resolvedAmbientPriors = await resolveRuntimeAmbientPriors(text, ambientPriors, currentGoal, activePolicy);
218
- const result = await eng.processInput(text, {
232
+ const resolvedActivePolicy = resolveRuntimeActivePolicy(activePolicy, currentTurnCorrection);
233
+ const resolvedAmbientPriors = await resolveRuntimeAmbientPriors(text, ambientPriors, currentGoal, resolvedActivePolicy, currentTurnCorrection);
234
+ const result = await safeProcessInput(eng, text, {
219
235
  userId,
220
236
  ambientPriors: resolvedAmbientPriors,
221
237
  currentGoal,
222
- activePolicy,
223
- });
238
+ activePolicy: resolvedActivePolicy,
239
+ currentTurnCorrection,
240
+ }, "mcp.processInput");
224
241
  return {
225
242
  content: [{
226
243
  type: "text",
@@ -257,13 +274,14 @@ server.tool("process_output", "Process the LLM's response through the emotional
257
274
  signalConfidence: z.number().min(0).max(1).optional().describe("Optional confidence for the supplied signals"),
258
275
  }, async ({ text, userId, signals, signalConfidence }) => {
259
276
  const eng = await getEngine();
260
- const result = await eng.processOutput(text, { userId, signals: signals, signalConfidence });
277
+ const result = await safeProcessOutput(eng, text, { userId, signals: signals, signalConfidence }, "mcp.processOutput");
261
278
  return {
262
279
  content: [{
263
280
  type: "text",
264
281
  text: JSON.stringify({
265
282
  cleanedText: result.cleanedText,
266
283
  stateChanged: result.stateChanged,
284
+ validationIssues: result.validationIssues ?? [],
267
285
  }, null, 2),
268
286
  }],
269
287
  };
@@ -54,7 +54,7 @@ export declare function psycheMiddleware(engine: PsycheEngine, _opts?: PsycheMid
54
54
  type: string;
55
55
  params: CallParams;
56
56
  }) => Promise<{
57
- system: string;
57
+ system: string | undefined;
58
58
  maxTokens?: number | undefined;
59
59
  prompt?: PromptMessage[];
60
60
  }>;
@@ -15,6 +15,7 @@
15
15
  // - wrapGenerate: process output, strip <psyche_update> tags
16
16
  // - wrapStream: buffer stream, detect & strip tags at end
17
17
  // ============================================================
18
+ import { composePsycheContext, safeProcessInput, safeProcessOutput } from "./fail-open.js";
18
19
  /**
19
20
  * Create Vercel AI SDK middleware that injects psyche emotional context
20
21
  * and processes LLM output for state updates.
@@ -48,7 +49,7 @@ export function psycheMiddleware(engine, _opts) {
48
49
  return {
49
50
  transformParams: async ({ params }) => {
50
51
  const userText = extractLastUserText(params.prompt ?? []);
51
- const result = await engine.processInput(userText);
52
+ const result = await safeProcessInput(engine, userText, undefined, "vercel-ai.processInput");
52
53
  const envelope = result.replyEnvelope;
53
54
  const generationControls = envelope?.generationControls ?? result.generationControls;
54
55
  const controls = {
@@ -57,19 +58,19 @@ export function psycheMiddleware(engine, _opts) {
57
58
  ? Math.min(params.maxTokens, generationControls.maxTokens)
58
59
  : generationControls?.maxTokens ?? (typeof params.maxTokens === "number" ? params.maxTokens : undefined),
59
60
  };
60
- const psycheContext = result.systemContext + "\n\n" + result.dynamicContext;
61
+ const psycheContext = composePsycheContext(result);
61
62
  return {
62
63
  ...params,
63
64
  ...(controls.maxTokens !== undefined ? { maxTokens: controls.maxTokens } : {}),
64
- system: params.system
65
- ? psycheContext + "\n\n" + params.system
66
- : psycheContext,
65
+ system: psycheContext
66
+ ? (params.system ? psycheContext + "\n\n" + params.system : psycheContext)
67
+ : params.system,
67
68
  };
68
69
  },
69
70
  wrapGenerate: async ({ doGenerate }) => {
70
71
  const result = await doGenerate();
71
72
  if (typeof result.text === "string") {
72
- const processed = await engine.processOutput(result.text);
73
+ const processed = await safeProcessOutput(engine, result.text, undefined, "vercel-ai.processOutput");
73
74
  return { ...result, text: processed.cleanedText };
74
75
  }
75
76
  return result;
@@ -134,7 +135,7 @@ export function psycheMiddleware(engine, _opts) {
134
135
  else if (chunk.type === "finish") {
135
136
  // Process full text through engine before finishing
136
137
  if (fullText) {
137
- await engine.processOutput(fullText);
138
+ await safeProcessOutput(engine, fullText, undefined, "vercel-ai.processOutput");
138
139
  }
139
140
  yield chunk;
140
141
  }
@@ -1,4 +1,4 @@
1
- import type { ActivePolicyRule, AmbientPriorView, CurrentGoal } from "./types.js";
1
+ import { type ActivePolicyRule, type AmbientPriorView, type CurrentGoal } from "./types.js";
2
2
  interface CommandResult {
3
3
  ok: boolean;
4
4
  stdout: string;
@@ -11,6 +11,7 @@ export interface ThrongletsAmbientRuntimeOptions {
11
11
  space?: string;
12
12
  goal?: CurrentGoal;
13
13
  activePolicy?: ActivePolicyRule[];
14
+ currentTurnCorrection?: string;
14
15
  limit?: number;
15
16
  timeoutMs?: number;
16
17
  runner?: CommandRunner;
@@ -18,7 +19,9 @@ export interface ThrongletsAmbientRuntimeOptions {
18
19
  export interface AmbientPriorResolutionOptions {
19
20
  explicit?: readonly AmbientPriorView[] | unknown;
20
21
  enabled?: boolean;
22
+ currentGoal?: CurrentGoal;
21
23
  activePolicy?: ActivePolicyRule[];
24
+ currentTurnCorrection?: string;
22
25
  thronglets?: ThrongletsAmbientRuntimeOptions;
23
26
  fetcher?: typeof fetchAmbientPriorsFromThronglets;
24
27
  }
@@ -1,4 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "./types.js";
2
3
  import { normalizeAmbientPriors } from "./ambient-priors.js";
3
4
  const DEFAULT_AMBIENT_LIMIT = 3;
4
5
  const DEFAULT_TIMEOUT_MS = 800;
@@ -64,6 +65,8 @@ export async function fetchAmbientPriorsFromThronglets(text, opts = {}) {
64
65
  const limit = Math.max(1, Math.min(5, opts.limit ?? DEFAULT_AMBIENT_LIMIT));
65
66
  const timeoutMs = Math.max(100, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
66
67
  const runner = opts.runner ?? defaultRunner;
68
+ const currentTurnCorrection = normalizeCurrentTurnCorrection(opts.currentTurnCorrection);
69
+ const activePolicy = resolveRuntimeActivePolicy(opts.activePolicy, currentTurnCorrection) ?? [];
67
70
  const args = [];
68
71
  if (dataDir && dataDir.trim()) {
69
72
  args.push("--data-dir", dataDir.trim());
@@ -74,7 +77,8 @@ export async function fetchAmbientPriorsFromThronglets(text, opts = {}) {
74
77
  space,
75
78
  goal,
76
79
  limit,
77
- active_policy: opts.activePolicy ?? [],
80
+ active_policy: activePolicy,
81
+ current_turn_correction: currentTurnCorrection,
78
82
  });
79
83
  try {
80
84
  const result = await runner(binaryPath, args, payload, timeoutMs);
@@ -99,7 +103,8 @@ export async function resolveAmbientPriorsForTurn(text, opts = {}) {
99
103
  const fetcher = opts.fetcher ?? fetchAmbientPriorsFromThronglets;
100
104
  const priors = await fetcher(text, {
101
105
  ...(opts.thronglets ?? {}),
102
- activePolicy: opts.activePolicy ?? opts.thronglets?.activePolicy,
106
+ activePolicy: resolveRuntimeActivePolicy(opts.activePolicy ?? opts.thronglets?.activePolicy, opts.currentTurnCorrection ?? opts.thronglets?.currentTurnCorrection),
107
+ currentTurnCorrection: normalizeCurrentTurnCorrection(opts.currentTurnCorrection ?? opts.thronglets?.currentTurnCorrection),
103
108
  });
104
109
  return priors.length > 0 ? priors : undefined;
105
110
  }
package/dist/core.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActivePolicyRule, AmbientPriorView, CurrentGoal, PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits, PolicyModifiers, ClassifierProvider, SubjectivityKernel, ResponseContract, GenerationControls, SessionBridgeState, ThrongletsExport, TurnObservability, WritebackCalibrationFeedback, WritebackSignalType, ExternalContinuityEnvelope, AppraisalAxes } from "./types.js";
1
+ import type { ActivePolicyRule, AmbientPriorView, CurrentGoal, PsycheState, StimulusType, Locale, MBTIType, OutcomeScore, PsycheMode, PersonalityTraits, PolicyModifiers, ClassifierProvider, SubjectivityKernel, ResponseContract, GenerationControls, SessionBridgeState, ThrongletsExport, TurnObservability, WritebackCalibrationFeedback, ExternalContinuityEnvelope, AppraisalAxes } from "./types.js";
2
2
  import type { StorageAdapter } from "./storage.js";
3
3
  import type { DiagnosticReport, SessionMetrics } from "./diagnostics.js";
4
4
  import type { ReplyEnvelope } from "./reply-envelope.js";
@@ -95,18 +95,27 @@ export interface ProcessInputOptions {
95
95
  ambientPriors?: AmbientPriorView[];
96
96
  currentGoal?: CurrentGoal;
97
97
  activePolicy?: ActivePolicyRule[];
98
+ currentTurnCorrection?: string;
98
99
  }
99
100
  export interface ProcessOutputResult {
100
101
  /** LLM output with <psyche_update> tags stripped */
101
102
  cleanedText: string;
102
103
  /** Whether self-state was meaningfully updated (contagion or psyche_update) */
103
104
  stateChanged: boolean;
105
+ /** Runtime validation issues ignored to preserve the main flow */
106
+ validationIssues?: ProcessOutputValidationIssue[];
104
107
  }
105
108
  export interface ProcessOutputOptions {
106
109
  userId?: string;
107
- signals?: WritebackSignalType[];
110
+ signals?: readonly string[];
108
111
  signalConfidence?: number;
109
112
  }
113
+ export interface ProcessOutputValidationIssue {
114
+ code: "invalid-writeback-signals";
115
+ level: "warning";
116
+ message: string;
117
+ ignoredSignals: string[];
118
+ }
110
119
  export interface ProcessOutcomeResult {
111
120
  /** Outcome evaluation score (-1 to 1) */
112
121
  outcomeScore: OutcomeScore;
package/dist/core.js CHANGED
@@ -11,7 +11,7 @@
11
11
  //
12
12
  // Orchestrates: self-state, appraisal, prompt, profiles, guards, learning
13
13
  // ============================================================
14
- import { normalizeActivePolicyRules, normalizeCurrentGoal } from "./types.js";
14
+ import { normalizeCurrentGoal, resolveRuntimeActivePolicy } from "./types.js";
15
15
  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";
16
16
  import { MemoryStorageAdapter } from "./storage.js";
17
17
  import { applyDecay, applyStimulus, applyContagion, clamp, describeEmotionalState } from "./chemistry.js";
@@ -34,6 +34,7 @@ import { deriveThrongletsExports } from "./thronglets-export.js";
34
34
  import { buildTurnObservability } from "./observability.js";
35
35
  import { DEFAULT_RELATIONSHIP_USER_ID, resolveRelationshipUserId } from "./relationship-key.js";
36
36
  import { normalizeAmbientPriors } from "./ambient-priors.js";
37
+ import { normalizeWritebackSignals } from "./writeback-signals.js";
37
38
  function formatWritebackFeedbackNote(feedback, locale) {
38
39
  const top = feedback?.[0];
39
40
  if (!top)
@@ -461,7 +462,7 @@ export class PsycheEngine {
461
462
  }
462
463
  const writebackNote = formatWritebackFeedbackNote(writebackFeedback, locale);
463
464
  const ambientPriors = normalizeAmbientPriors(opts?.ambientPriors);
464
- const activePolicy = normalizeActivePolicyRules(opts?.activePolicy) ?? [];
465
+ const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, opts?.currentTurnCorrection) ?? [];
465
466
  const currentGoal = normalizeCurrentGoal(opts?.currentGoal)
466
467
  ?? ambientPriors.find((prior) => prior.goal)?.goal;
467
468
  const ambientPriorContext = buildAmbientPriorContext(ambientPriors, locale);
@@ -564,6 +565,7 @@ export class PsycheEngine {
564
565
  async processOutput(text, opts) {
565
566
  let state = this.ensureInitialized();
566
567
  let stateChanged = false;
568
+ const validationIssues = [];
567
569
  // Emotional contagion from empathy log
568
570
  if (state.empathyLog?.userState && this.cfg.emotionalContagionRate > 0) {
569
571
  const userEmotion = state.empathyLog.userState.toLowerCase();
@@ -615,6 +617,18 @@ export class PsycheEngine {
615
617
  // Parse and merge <psyche_update> from LLM output
616
618
  let combinedSignals = [];
617
619
  let combinedSignalConfidence = opts?.signalConfidence;
620
+ const recordInvalidSignals = (source, invalidSignals) => {
621
+ if (invalidSignals.length === 0)
622
+ return;
623
+ const issue = {
624
+ code: "invalid-writeback-signals",
625
+ level: "warning",
626
+ message: `Ignored unsupported writeback signals from ${source}`,
627
+ ignoredSignals: invalidSignals,
628
+ };
629
+ validationIssues.push(issue);
630
+ this.recordDiagnosticError("processOutput", new Error(`${issue.message}: ${invalidSignals.join(", ")}`));
631
+ };
618
632
  if (text.includes("<psyche_update>")) {
619
633
  const parseResult = parsePsycheUpdate(text, NOOP_LOGGER);
620
634
  if (parseResult) {
@@ -645,10 +659,13 @@ export class PsycheEngine {
645
659
  combinedSignals.push(...parseResult.signals);
646
660
  combinedSignalConfidence = Math.max(combinedSignalConfidence ?? 0, parseResult.signalConfidence ?? 0);
647
661
  }
662
+ recordInvalidSignals("llm", parseResult.invalidSignals ?? []);
648
663
  }
649
664
  }
650
665
  if (opts?.signals && opts.signals.length > 0) {
651
- combinedSignals.push(...opts.signals);
666
+ const normalizedSignals = normalizeWritebackSignals(opts.signals);
667
+ combinedSignals.push(...normalizedSignals.validSignals);
668
+ recordInvalidSignals("host", normalizedSignals.invalidSignals);
652
669
  combinedSignalConfidence = Math.max(combinedSignalConfidence ?? 0, opts.signalConfidence ?? 0);
653
670
  }
654
671
  if (combinedSignals.length > 0) {
@@ -681,7 +698,11 @@ export class PsycheEngine {
681
698
  .replace(/\n{3,}/g, "\n\n")
682
699
  .trim();
683
700
  }
684
- return { cleanedText, stateChanged };
701
+ return {
702
+ cleanedText,
703
+ stateChanged,
704
+ ...(validationIssues.length > 0 ? { validationIssues } : {}),
705
+ };
685
706
  }
686
707
  /**
687
708
  * Phase 3 (optional): Explicitly evaluate the outcome of the last interaction.
package/dist/prompt.js CHANGED
@@ -1094,6 +1094,10 @@ export function buildCompactContext(state, userId, opts) {
1094
1094
  if (unified)
1095
1095
  parts.push(unified);
1096
1096
  }
1097
+ const activePolicyContext = buildActivePolicyContext(opts?.activePolicy, locale);
1098
+ if (activePolicyContext) {
1099
+ parts.push(activePolicyContext);
1100
+ }
1097
1101
  // ── 9. Overlay + channel + writeback ──
1098
1102
  appendCompactOverlaySections(parts, locale, opts);
1099
1103
  if (opts?.channelType) {
@@ -97,6 +97,8 @@ export interface PsycheUpdateResult {
97
97
  llmStimulus?: StimulusType;
98
98
  /** Sparse agent-authored writeback signals */
99
99
  signals?: WritebackSignalType[];
100
+ /** Unsupported writeback signals that were ignored */
101
+ invalidSignals?: string[];
100
102
  /** Optional writeback confidence */
101
103
  signalConfidence?: number;
102
104
  }
@@ -12,6 +12,7 @@ import { t } from "./i18n.js";
12
12
  import { computeSelfReflection } from "./self-recognition.js";
13
13
  import { DEFAULT_RELATIONSHIP_USER_ID, resolveRelationshipUserId } from "./relationship-key.js";
14
14
  import { describeSnapshotResidue, summarizeSnapshotMarkers } from "./appraisal-markers.js";
15
+ import { normalizeWritebackSignals } from "./writeback-signals.js";
15
16
  const STATE_FILE = "psyche-state.json";
16
17
  const PSYCHE_MD = "PSYCHE.md";
17
18
  const IDENTITY_MD = "IDENTITY.md";
@@ -792,28 +793,20 @@ export function parsePsycheUpdate(text, logger = NOOP_LOGGER) {
792
793
  llmStimulus = candidate;
793
794
  }
794
795
  }
795
- const VALID_WRITEBACK_SIGNALS = new Set([
796
- "trust_up",
797
- "trust_down",
798
- "boundary_set",
799
- "boundary_soften",
800
- "repair_attempt",
801
- "repair_landed",
802
- "closeness_invite",
803
- "withdrawal_mark",
804
- "self_assertion",
805
- "task_recenter",
806
- ]);
807
796
  let signals;
797
+ let invalidSignals;
808
798
  const signalsMatch = block.match(/signals\s*[::]\s*([^\n]+)/i);
809
799
  if (signalsMatch) {
810
800
  const parsed = signalsMatch[1]
811
801
  .split(/[,\s|]+/)
812
802
  .map((item) => item.trim())
813
- .filter(Boolean)
814
- .filter((item) => VALID_WRITEBACK_SIGNALS.has(item));
815
- if (parsed.length > 0) {
816
- signals = [...new Set(parsed)];
803
+ .filter(Boolean);
804
+ const normalized = normalizeWritebackSignals(parsed);
805
+ if (normalized.validSignals.length > 0) {
806
+ signals = normalized.validSignals;
807
+ }
808
+ if (normalized.invalidSignals.length > 0) {
809
+ invalidSignals = normalized.invalidSignals;
817
810
  }
818
811
  }
819
812
  let signalConfidence;
@@ -858,6 +851,9 @@ export function parsePsycheUpdate(text, logger = NOOP_LOGGER) {
858
851
  if (signals) {
859
852
  result.signals = signals;
860
853
  }
854
+ if (invalidSignals) {
855
+ result.invalidSignals = invalidSignals;
856
+ }
861
857
  if (signalConfidence !== undefined) {
862
858
  result.signalConfidence = signalConfidence;
863
859
  }
package/dist/types.d.ts CHANGED
@@ -593,8 +593,10 @@ export interface ActivePolicyRule {
593
593
  scope: ActivePolicyScope;
594
594
  summary: string;
595
595
  }
596
+ export declare function normalizeCurrentTurnCorrection(value: unknown): string | undefined;
596
597
  export declare function normalizeCurrentGoal(value: unknown): CurrentGoal | undefined;
597
598
  export declare function normalizeActivePolicyRules(value: unknown, limit?: number): ActivePolicyRule[] | undefined;
599
+ export declare function resolveRuntimeActivePolicy(activePolicy: unknown, currentTurnCorrection?: unknown, limit?: number): ActivePolicyRule[] | undefined;
598
600
  export interface AmbientPriorView {
599
601
  summary: string;
600
602
  confidence: number;
package/dist/types.js CHANGED
@@ -224,6 +224,12 @@ export const AMBIENT_POLICY_STATES = [
224
224
  "method-conflict",
225
225
  "stable-path",
226
226
  ];
227
+ export function normalizeCurrentTurnCorrection(value) {
228
+ if (typeof value !== "string")
229
+ return undefined;
230
+ const summary = value.trim().replace(/\s+/g, " ");
231
+ return summary.length > 0 ? summary : undefined;
232
+ }
227
233
  export function normalizeCurrentGoal(value) {
228
234
  return typeof value === "string" && CURRENT_GOALS.includes(value)
229
235
  ? value
@@ -251,6 +257,24 @@ export function normalizeActivePolicyRules(value, limit = 3) {
251
257
  .slice(0, Math.max(1, limit));
252
258
  return normalized.length > 0 ? normalized : undefined;
253
259
  }
260
+ export function resolveRuntimeActivePolicy(activePolicy, currentTurnCorrection, limit = 3) {
261
+ const explicit = normalizeActivePolicyRules(activePolicy, limit) ?? [];
262
+ const correction = normalizeCurrentTurnCorrection(currentTurnCorrection);
263
+ if (!correction)
264
+ return explicit.length > 0 ? explicit : undefined;
265
+ const merged = [{
266
+ id: "task:current-turn-correction",
267
+ strength: "hard",
268
+ scope: "task",
269
+ summary: correction,
270
+ }];
271
+ for (const rule of explicit) {
272
+ if (rule.summary === correction)
273
+ continue;
274
+ merged.push(rule);
275
+ }
276
+ return merged.slice(0, Math.max(1, limit));
277
+ }
254
278
  /** Default empty trait drift state */
255
279
  export const DEFAULT_TRAIT_DRIFT = {
256
280
  accumulators: {
@@ -0,0 +1,8 @@
1
+ import type { WritebackSignalType } from "./types.js";
2
+ export declare const WRITEBACK_SIGNAL_VALUES: readonly ["trust_up", "trust_down", "boundary_set", "boundary_soften", "repair_attempt", "repair_landed", "closeness_invite", "withdrawal_mark", "self_assertion", "task_recenter"];
3
+ export interface NormalizedWritebackSignals {
4
+ validSignals: WritebackSignalType[];
5
+ invalidSignals: string[];
6
+ }
7
+ export declare function coerceWritebackSignalInput(value: unknown): string[] | undefined;
8
+ export declare function normalizeWritebackSignals(value: unknown): NormalizedWritebackSignals;
@@ -0,0 +1,39 @@
1
+ export const WRITEBACK_SIGNAL_VALUES = [
2
+ "trust_up",
3
+ "trust_down",
4
+ "boundary_set",
5
+ "boundary_soften",
6
+ "repair_attempt",
7
+ "repair_landed",
8
+ "closeness_invite",
9
+ "withdrawal_mark",
10
+ "self_assertion",
11
+ "task_recenter",
12
+ ];
13
+ const WRITEBACK_SIGNAL_SET = new Set(WRITEBACK_SIGNAL_VALUES);
14
+ export function coerceWritebackSignalInput(value) {
15
+ if (!Array.isArray(value))
16
+ return undefined;
17
+ const signals = value
18
+ .filter((item) => typeof item === "string")
19
+ .map((item) => item.trim())
20
+ .filter(Boolean);
21
+ return signals.length > 0 ? [...new Set(signals)] : undefined;
22
+ }
23
+ export function normalizeWritebackSignals(value) {
24
+ const rawSignals = coerceWritebackSignalInput(value) ?? [];
25
+ const validSignals = [];
26
+ const invalidSignals = [];
27
+ for (const signal of rawSignals) {
28
+ if (WRITEBACK_SIGNAL_SET.has(signal)) {
29
+ validSignals.push(signal);
30
+ }
31
+ else {
32
+ invalidSignals.push(signal);
33
+ }
34
+ }
35
+ return {
36
+ validSignals,
37
+ invalidSignals,
38
+ };
39
+ }
@@ -2,7 +2,7 @@
2
2
  "id": "psyche-ai",
3
3
  "name": "Artificial Psyche",
4
4
  "description": "AI-first subjectivity kernel for agents with continuous appraisal, relation dynamics, and adaptive reply loops",
5
- "version": "11.5.4",
5
+ "version": "11.5.6",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "psyche-ai",
3
- "version": "11.5.4",
3
+ "version": "11.5.6",
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",