psyche-ai 11.5.4 → 11.5.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/README.md +23 -0
- package/dist/adapters/claude-sdk.js +17 -2
- package/dist/adapters/http.js +12 -2
- package/dist/adapters/langchain.d.ts +7 -0
- package/dist/adapters/langchain.js +19 -3
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +27 -11
- package/dist/adapters/proxy.js +0 -0
- package/dist/ambient-runtime.d.ts +4 -1
- package/dist/ambient-runtime.js +7 -2
- package/dist/cli.js +0 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +2 -2
- package/dist/prompt.js +4 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +24 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/experience.d.ts +0 -34
- package/dist/experience.js +0 -200
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,6 +28,7 @@
|
|
|
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";
|
|
@@ -107,9 +108,12 @@ export class PsycheClaudeSDK {
|
|
|
107
108
|
ambient: opts?.ambient === true ? {} : (opts?.ambient || undefined),
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
|
-
async resolveAmbientPriors(userMessage) {
|
|
111
|
+
async resolveAmbientPriors(userMessage, currentGoal, activePolicy, currentTurnCorrection) {
|
|
111
112
|
return resolveAmbientPriorsForTurn(userMessage, {
|
|
112
113
|
enabled: Boolean(this.opts.ambient),
|
|
114
|
+
currentGoal,
|
|
115
|
+
activePolicy,
|
|
116
|
+
currentTurnCorrection,
|
|
113
117
|
thronglets: this.opts.ambient
|
|
114
118
|
? {
|
|
115
119
|
...this.opts.ambient,
|
|
@@ -166,10 +170,21 @@ export class PsycheClaudeSDK {
|
|
|
166
170
|
sessionId: runtimeContext.sessionId ?? self.lastRuntimeContext.sessionId,
|
|
167
171
|
};
|
|
168
172
|
const userMessage = input.user_message ?? "";
|
|
169
|
-
const
|
|
173
|
+
const currentTurnCorrection = normalizeCurrentTurnCorrection(input.current_turn_correction
|
|
174
|
+
?? input.currentTurnCorrection
|
|
175
|
+
?? input.task_correction
|
|
176
|
+
?? input.taskCorrection
|
|
177
|
+
?? input.explicit_instruction
|
|
178
|
+
?? input.explicitInstruction);
|
|
179
|
+
const currentGoal = normalizeCurrentGoal(input.current_goal ?? input.currentGoal);
|
|
180
|
+
const activePolicy = resolveRuntimeActivePolicy(input.active_policy ?? input.activePolicy, currentTurnCorrection);
|
|
181
|
+
const ambientPriors = await self.resolveAmbientPriors(userMessage, currentGoal, activePolicy, currentTurnCorrection);
|
|
170
182
|
const result = await self.engine.processInput(userMessage, {
|
|
171
183
|
userId: self.opts.userId,
|
|
172
184
|
ambientPriors,
|
|
185
|
+
currentGoal,
|
|
186
|
+
activePolicy,
|
|
187
|
+
currentTurnCorrection,
|
|
173
188
|
});
|
|
174
189
|
self.lastInputResult = result;
|
|
175
190
|
// Cache Thronglets exports from this turn
|
package/dist/adapters/http.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// Zero dependencies — uses node:http only.
|
|
17
17
|
// ============================================================
|
|
18
18
|
import { createServer } from "node:http";
|
|
19
|
-
import {
|
|
19
|
+
import { normalizeCurrentGoal, normalizeCurrentTurnCorrection, resolveRuntimeActivePolicy, } from "../types.js";
|
|
20
20
|
import { parseAmbientPriorsInput } from "../ambient-runtime.js";
|
|
21
21
|
import { computeOverlay } from "../overlay.js";
|
|
22
22
|
const VALID_WRITEBACK_SIGNALS = new Set([
|
|
@@ -40,6 +40,14 @@ function parseSignals(value) {
|
|
|
40
40
|
function parseAmbientPriors(value) {
|
|
41
41
|
return parseAmbientPriorsInput(value);
|
|
42
42
|
}
|
|
43
|
+
function parseCurrentTurnCorrection(body) {
|
|
44
|
+
return normalizeCurrentTurnCorrection(body.currentTurnCorrection
|
|
45
|
+
?? body.current_turn_correction
|
|
46
|
+
?? body.taskCorrection
|
|
47
|
+
?? body.task_correction
|
|
48
|
+
?? body.explicitInstruction
|
|
49
|
+
?? body.explicit_instruction);
|
|
50
|
+
}
|
|
43
51
|
// ── Server ───────────────────────────────────────────────────
|
|
44
52
|
/**
|
|
45
53
|
* Create an HTTP server that exposes PsycheEngine via REST API.
|
|
@@ -94,11 +102,13 @@ export function createPsycheServer(engine, opts) {
|
|
|
94
102
|
// POST /process-input
|
|
95
103
|
if (req.method === "POST" && url.pathname === "/process-input") {
|
|
96
104
|
const body = await readBody(req);
|
|
105
|
+
const currentTurnCorrection = parseCurrentTurnCorrection(body);
|
|
97
106
|
const result = await engine.processInput(body.text ?? "", {
|
|
98
107
|
userId: body.userId,
|
|
99
108
|
ambientPriors: parseAmbientPriors(body.ambientPriors),
|
|
100
109
|
currentGoal: normalizeCurrentGoal(body.currentGoal),
|
|
101
|
-
activePolicy:
|
|
110
|
+
activePolicy: resolveRuntimeActivePolicy(body.activePolicy, currentTurnCorrection),
|
|
111
|
+
currentTurnCorrection,
|
|
102
112
|
});
|
|
103
113
|
json(res, 200, {
|
|
104
114
|
systemContext: result.systemContext,
|
|
@@ -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;
|
|
@@ -44,6 +45,9 @@ export declare class PsycheLangChain {
|
|
|
44
45
|
*/
|
|
45
46
|
getSystemMessage(userText: string, opts?: {
|
|
46
47
|
userId?: string;
|
|
48
|
+
currentGoal?: CurrentGoal;
|
|
49
|
+
activePolicy?: ActivePolicyRule[];
|
|
50
|
+
currentTurnCorrection?: string;
|
|
47
51
|
}): Promise<string>;
|
|
48
52
|
/**
|
|
49
53
|
* Prepare both prompt text and mechanical invocation hints for a LangChain call.
|
|
@@ -54,6 +58,9 @@ export declare class PsycheLangChain {
|
|
|
54
58
|
prepareInvocation(userText: string, opts?: {
|
|
55
59
|
userId?: string;
|
|
56
60
|
maxTokens?: number;
|
|
61
|
+
currentGoal?: CurrentGoal;
|
|
62
|
+
activePolicy?: ActivePolicyRule[];
|
|
63
|
+
currentTurnCorrection?: string;
|
|
57
64
|
}): Promise<{
|
|
58
65
|
systemMessage: string;
|
|
59
66
|
maxTokens?: number;
|
|
@@ -12,6 +12,7 @@
|
|
|
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";
|
|
16
17
|
/**
|
|
17
18
|
* LangChain integration helper for PsycheEngine.
|
|
@@ -64,10 +65,13 @@ export class PsycheLangChain {
|
|
|
64
65
|
const parsed = signals.filter((signal) => this.validSignals.has(signal));
|
|
65
66
|
return parsed.length > 0 ? [...new Set(parsed)] : undefined;
|
|
66
67
|
}
|
|
67
|
-
async resolveAmbientPriors(userText) {
|
|
68
|
+
async resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection) {
|
|
68
69
|
const ambient = this.opts.ambient;
|
|
69
70
|
return resolveAmbientPriorsForTurn(userText, {
|
|
70
71
|
enabled: Boolean(ambient),
|
|
72
|
+
currentGoal,
|
|
73
|
+
activePolicy,
|
|
74
|
+
currentTurnCorrection,
|
|
71
75
|
thronglets: ambient
|
|
72
76
|
? {
|
|
73
77
|
...(ambient === true ? {} : ambient),
|
|
@@ -83,9 +87,15 @@ export class PsycheLangChain {
|
|
|
83
87
|
* Call this BEFORE the LLM invocation.
|
|
84
88
|
*/
|
|
85
89
|
async getSystemMessage(userText, opts) {
|
|
90
|
+
const currentTurnCorrection = normalizeCurrentTurnCorrection(opts?.currentTurnCorrection);
|
|
91
|
+
const currentGoal = normalizeCurrentGoal(opts?.currentGoal);
|
|
92
|
+
const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, currentTurnCorrection);
|
|
86
93
|
const result = await this.engine.processInput(userText, {
|
|
87
94
|
...opts,
|
|
88
|
-
|
|
95
|
+
currentGoal,
|
|
96
|
+
activePolicy,
|
|
97
|
+
currentTurnCorrection,
|
|
98
|
+
ambientPriors: await this.resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection),
|
|
89
99
|
});
|
|
90
100
|
return result.systemContext + "\n\n" + result.dynamicContext;
|
|
91
101
|
}
|
|
@@ -96,9 +106,15 @@ export class PsycheLangChain {
|
|
|
96
106
|
* instead of re-parsing prompt prose.
|
|
97
107
|
*/
|
|
98
108
|
async prepareInvocation(userText, opts) {
|
|
109
|
+
const currentTurnCorrection = normalizeCurrentTurnCorrection(opts?.currentTurnCorrection);
|
|
110
|
+
const currentGoal = normalizeCurrentGoal(opts?.currentGoal);
|
|
111
|
+
const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, currentTurnCorrection);
|
|
99
112
|
const result = await this.engine.processInput(userText, {
|
|
100
113
|
...opts,
|
|
101
|
-
|
|
114
|
+
currentGoal,
|
|
115
|
+
activePolicy,
|
|
116
|
+
currentTurnCorrection,
|
|
117
|
+
ambientPriors: await this.resolveAmbientPriors(userText, currentGoal, activePolicy, currentTurnCorrection),
|
|
102
118
|
});
|
|
103
119
|
const generationControls = result.replyEnvelope?.generationControls ?? result.generationControls;
|
|
104
120
|
const controls = {
|
package/dist/adapters/mcp.d.ts
CHANGED
|
@@ -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 };
|
package/dist/adapters/mcp.js
CHANGED
|
@@ -32,7 +32,7 @@ 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
38
|
const PACKAGE_VERSION = await getPackageVersion();
|
|
@@ -126,19 +126,32 @@ async function getEngine() {
|
|
|
126
126
|
await engine.initialize();
|
|
127
127
|
return engine;
|
|
128
128
|
}
|
|
129
|
-
export async function resolveRuntimeAmbientPriors(text, explicit, currentGoal, activePolicy, opts = DEFAULT_MCP_AMBIENT_OPTIONS) {
|
|
130
|
-
const
|
|
129
|
+
export async function resolveRuntimeAmbientPriors(text, explicit, currentGoal, activePolicy, currentTurnCorrectionOrOpts, opts = DEFAULT_MCP_AMBIENT_OPTIONS) {
|
|
130
|
+
const currentTurnCorrection = typeof currentTurnCorrectionOrOpts === "string"
|
|
131
|
+
? currentTurnCorrectionOrOpts
|
|
132
|
+
: undefined;
|
|
133
|
+
const resolvedOpts = (typeof currentTurnCorrectionOrOpts === "object"
|
|
134
|
+
&& currentTurnCorrectionOrOpts !== null)
|
|
135
|
+
? currentTurnCorrectionOrOpts
|
|
136
|
+
: opts;
|
|
137
|
+
const normalizedCorrection = normalizeCurrentTurnCorrection(currentTurnCorrection);
|
|
138
|
+
const resolvedActivePolicy = resolveRuntimeActivePolicy(activePolicy, normalizedCorrection);
|
|
139
|
+
const throngletsOptions = resolvedOpts.thronglets || currentGoal || resolvedActivePolicy?.length || normalizedCorrection
|
|
131
140
|
? {
|
|
132
|
-
...(
|
|
133
|
-
goal: currentGoal ??
|
|
134
|
-
activePolicy:
|
|
141
|
+
...(resolvedOpts.thronglets ?? {}),
|
|
142
|
+
goal: currentGoal ?? resolvedOpts.thronglets?.goal,
|
|
143
|
+
activePolicy: resolvedActivePolicy ?? resolvedOpts.thronglets?.activePolicy,
|
|
144
|
+
currentTurnCorrection: normalizedCorrection ?? resolvedOpts.thronglets?.currentTurnCorrection,
|
|
135
145
|
}
|
|
136
146
|
: undefined;
|
|
137
147
|
return resolveAmbientPriorsForTurn(text, {
|
|
138
148
|
explicit,
|
|
139
|
-
enabled:
|
|
149
|
+
enabled: resolvedOpts.mode !== "off",
|
|
150
|
+
currentGoal,
|
|
151
|
+
currentTurnCorrection: normalizedCorrection,
|
|
152
|
+
activePolicy: resolvedActivePolicy,
|
|
140
153
|
thronglets: throngletsOptions,
|
|
141
|
-
fetcher:
|
|
154
|
+
fetcher: resolvedOpts.fetcher ?? fetchAmbientPriorsFromThronglets,
|
|
142
155
|
});
|
|
143
156
|
}
|
|
144
157
|
// ── MCP Server ─────────────────────────────────────────────
|
|
@@ -212,14 +225,17 @@ server.tool("process_input", "Process user input through the emotional engine. R
|
|
|
212
225
|
scope: z.enum(["task", "project"]),
|
|
213
226
|
summary: z.string(),
|
|
214
227
|
})).optional().describe("Optional explicit current-turn method policy view. Runtime-only; not persisted as self-state."),
|
|
215
|
-
|
|
228
|
+
currentTurnCorrection: z.string().optional().describe("Optional explicit current-turn correction. Compiles into a task-scoped hard policy for this turn only."),
|
|
229
|
+
}, async ({ text, userId, ambientPriors, currentGoal, activePolicy, currentTurnCorrection }) => {
|
|
216
230
|
const eng = await getEngine();
|
|
217
|
-
const
|
|
231
|
+
const resolvedActivePolicy = resolveRuntimeActivePolicy(activePolicy, currentTurnCorrection);
|
|
232
|
+
const resolvedAmbientPriors = await resolveRuntimeAmbientPriors(text, ambientPriors, currentGoal, resolvedActivePolicy, currentTurnCorrection);
|
|
218
233
|
const result = await eng.processInput(text, {
|
|
219
234
|
userId,
|
|
220
235
|
ambientPriors: resolvedAmbientPriors,
|
|
221
236
|
currentGoal,
|
|
222
|
-
activePolicy,
|
|
237
|
+
activePolicy: resolvedActivePolicy,
|
|
238
|
+
currentTurnCorrection,
|
|
223
239
|
});
|
|
224
240
|
return {
|
|
225
241
|
content: [{
|
package/dist/adapters/proxy.js
CHANGED
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
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
|
}
|
package/dist/ambient-runtime.js
CHANGED
|
@@ -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:
|
|
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/cli.js
CHANGED
|
File without changes
|
package/dist/core.d.ts
CHANGED
|
@@ -95,6 +95,7 @@ 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 */
|
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 {
|
|
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";
|
|
@@ -461,7 +461,7 @@ export class PsycheEngine {
|
|
|
461
461
|
}
|
|
462
462
|
const writebackNote = formatWritebackFeedbackNote(writebackFeedback, locale);
|
|
463
463
|
const ambientPriors = normalizeAmbientPriors(opts?.ambientPriors);
|
|
464
|
-
const activePolicy =
|
|
464
|
+
const activePolicy = resolveRuntimeActivePolicy(opts?.activePolicy, opts?.currentTurnCorrection) ?? [];
|
|
465
465
|
const currentGoal = normalizeCurrentGoal(opts?.currentGoal)
|
|
466
466
|
?? ambientPriors.find((prior) => prior.goal)?.goal;
|
|
467
467
|
const ambientPriorContext = buildAmbientPriorContext(ambientPriors, locale);
|
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) {
|
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: {
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "11.5.5",
|
|
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.
|
|
3
|
+
"version": "11.5.5",
|
|
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",
|
package/dist/experience.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { ChemicalState, StimulusType, AppraisalAxes, PsycheMode, ClassificationResult, ExperienceResult, Locale } from "./types.js";
|
|
2
|
-
export interface ExperienceContext {
|
|
3
|
-
/** Current chemistry — shapes how input is interpreted */
|
|
4
|
-
current: ChemicalState;
|
|
5
|
-
/** Personality baseline — deviation from baseline = subjective lens */
|
|
6
|
-
baseline: ChemicalState;
|
|
7
|
-
/** Residue from previous turns — carry-forward of unresolved tension */
|
|
8
|
-
previousAppraisal?: AppraisalAxes;
|
|
9
|
-
/** Recent stimulus history for contextual priming in classifier */
|
|
10
|
-
recentStimuli?: (StimulusType | null)[];
|
|
11
|
-
/** Operating mode */
|
|
12
|
-
mode?: PsycheMode;
|
|
13
|
-
/** Trust level from relationship (0-100). Low trust discounts positive signals. */
|
|
14
|
-
trust?: number;
|
|
15
|
-
/** Locale for classifier */
|
|
16
|
-
locale?: Locale;
|
|
17
|
-
/**
|
|
18
|
-
* Pre-classified results from external classifier (pluggable provider + LLM fallback).
|
|
19
|
-
* When provided, the experience module skips its own classification and uses these
|
|
20
|
-
* as raw perception to be modulated by subjectivity.
|
|
21
|
-
*/
|
|
22
|
-
rawClassifications?: ClassificationResult[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Compute the subjective experience of an input.
|
|
26
|
-
*
|
|
27
|
-
* Text passes through the self exactly once. The result already
|
|
28
|
-
* reflects "who I am" — my appraisal history, my current chemistry,
|
|
29
|
-
* my trust in this person.
|
|
30
|
-
*
|
|
31
|
-
* Returns weighted stimuli (for chemistry application) and appraisal
|
|
32
|
-
* axes (for relation dynamics and residue persistence).
|
|
33
|
-
*/
|
|
34
|
-
export declare function computeExperience(text: string, ctx: ExperienceContext): ExperienceResult;
|
package/dist/experience.js
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Unified Subjective Experience
|
|
3
|
-
//
|
|
4
|
-
// First principle: classification IS subjectivity.
|
|
5
|
-
// How I categorise your words = how I experience your words.
|
|
6
|
-
// This module folds classification, appraisal, and state
|
|
7
|
-
// modulation into a single act of perception.
|
|
8
|
-
//
|
|
9
|
-
// Before: classify(text) → label → applyStimulus(label)
|
|
10
|
-
// appraise(text) → axes (separate, after chemistry)
|
|
11
|
-
//
|
|
12
|
-
// After: experience(text, self) → { stimuli, appraisal }
|
|
13
|
-
// The same input through different selves produces
|
|
14
|
-
// different experiences. That IS having a self.
|
|
15
|
-
// ============================================================
|
|
16
|
-
import { classifyStimulus } from "./classify.js";
|
|
17
|
-
import { computeAppraisalAxes } from "./appraisal.js";
|
|
18
|
-
/**
|
|
19
|
-
* Compute the subjective experience of an input.
|
|
20
|
-
*
|
|
21
|
-
* Text passes through the self exactly once. The result already
|
|
22
|
-
* reflects "who I am" — my appraisal history, my current chemistry,
|
|
23
|
-
* my trust in this person.
|
|
24
|
-
*
|
|
25
|
-
* Returns weighted stimuli (for chemistry application) and appraisal
|
|
26
|
-
* axes (for relation dynamics and residue persistence).
|
|
27
|
-
*/
|
|
28
|
-
export function computeExperience(text, ctx) {
|
|
29
|
-
if (!text.trim()) {
|
|
30
|
-
return {
|
|
31
|
-
stimuli: [{ type: "casual", weight: 1 }],
|
|
32
|
-
primary: null,
|
|
33
|
-
confidence: 0,
|
|
34
|
-
appraisal: computeAppraisalAxes(text, {
|
|
35
|
-
mode: ctx.mode,
|
|
36
|
-
previous: ctx.previousAppraisal,
|
|
37
|
-
}),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
// ── 1. Raw perception: what the words say ──────────────────
|
|
41
|
-
// Use externally-provided classifications (pluggable classifier + LLM fallback)
|
|
42
|
-
// or fall back to built-in classifier.
|
|
43
|
-
const raw = ctx.rawClassifications ?? classifyStimulus(text, ctx.recentStimuli);
|
|
44
|
-
if (raw.length === 0) {
|
|
45
|
-
return {
|
|
46
|
-
stimuli: [{ type: "casual", weight: 1 }],
|
|
47
|
-
primary: null,
|
|
48
|
-
confidence: 0.3,
|
|
49
|
-
appraisal: computeAppraisalAxes(text, {
|
|
50
|
-
mode: ctx.mode,
|
|
51
|
-
previous: ctx.previousAppraisal,
|
|
52
|
-
}),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
// ── 2. Appraisal: what the words mean to me ───────────────
|
|
56
|
-
// Computed WITHOUT stimulus param — no circularity.
|
|
57
|
-
// The appraisal reads the text through my residue and mode,
|
|
58
|
-
// not through a classification that hasn't been subjectified yet.
|
|
59
|
-
const appraisal = computeAppraisalAxes(text, {
|
|
60
|
-
mode: ctx.mode,
|
|
61
|
-
previous: ctx.previousAppraisal,
|
|
62
|
-
});
|
|
63
|
-
// ── 3. Subjective modulation ──────────────────────────────
|
|
64
|
-
// My appraisal and state color my interpretation of the raw signal.
|
|
65
|
-
const modulated = modulateBySubjectivity(raw, appraisal, ctx);
|
|
66
|
-
// ── 4. Normalize to probability distribution ──────────────
|
|
67
|
-
const totalWeight = modulated.reduce((sum, s) => sum + s.weight, 0);
|
|
68
|
-
const stimuli = totalWeight > 0
|
|
69
|
-
? modulated.map(s => ({ type: s.type, weight: s.weight / totalWeight }))
|
|
70
|
-
: [{ type: "casual", weight: 1 }];
|
|
71
|
-
// Sort by weight descending
|
|
72
|
-
stimuli.sort((a, b) => b.weight - a.weight);
|
|
73
|
-
// ── 5. Enrich appraisal from experience ───────────────────
|
|
74
|
-
// The experienced stimulus feeds back to deepen appraisal residue.
|
|
75
|
-
// This is NOT circular: it doesn't change classification, only
|
|
76
|
-
// enriches the persisted residue for subsequent turns.
|
|
77
|
-
const primary = stimuli[0];
|
|
78
|
-
enrichAppraisalFromExperience(appraisal, primary.type, primary.weight);
|
|
79
|
-
return {
|
|
80
|
-
stimuli,
|
|
81
|
-
primary: primary.weight >= 0.15 ? primary.type : null,
|
|
82
|
-
confidence: raw[0].confidence,
|
|
83
|
-
appraisal,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
// ── Subjective modulation ───────────────────────────────────
|
|
87
|
-
/**
|
|
88
|
-
* The lens of the self: appraisal and state modulate raw classification.
|
|
89
|
-
*
|
|
90
|
-
* This is where "having a self" happens computationally.
|
|
91
|
-
* The same praise, passing through a threatened self vs. a secure self,
|
|
92
|
-
* produces different weight distributions.
|
|
93
|
-
*/
|
|
94
|
-
function modulateBySubjectivity(raw, appraisal, ctx) {
|
|
95
|
-
return raw.map(({ type, confidence }) => {
|
|
96
|
-
let weight = confidence;
|
|
97
|
-
// ── Appraisal lens ──
|
|
98
|
-
// Identity threat: praise feels suspicious, criticism cuts deeper
|
|
99
|
-
if (appraisal.identityThreat > 0.3) {
|
|
100
|
-
const t = appraisal.identityThreat;
|
|
101
|
-
if (type === "praise" || type === "validation")
|
|
102
|
-
weight *= 1 - t * 0.5;
|
|
103
|
-
if (type === "criticism" || type === "authority" || type === "sarcasm")
|
|
104
|
-
weight *= 1 + t * 0.4;
|
|
105
|
-
}
|
|
106
|
-
// Attachment pull: closeness signals amplified
|
|
107
|
-
if (appraisal.attachmentPull > 0.3) {
|
|
108
|
-
const p = appraisal.attachmentPull;
|
|
109
|
-
if (type === "intimacy" || type === "vulnerability" || type === "validation")
|
|
110
|
-
weight *= 1 + p * 0.3;
|
|
111
|
-
}
|
|
112
|
-
// Abandonment risk: neutral feels cold, neglect is devastating
|
|
113
|
-
if (appraisal.abandonmentRisk > 0.3) {
|
|
114
|
-
const r = appraisal.abandonmentRisk;
|
|
115
|
-
if (type === "neglect" || type === "boredom")
|
|
116
|
-
weight *= 1 + r * 0.5;
|
|
117
|
-
if (type === "casual")
|
|
118
|
-
weight *= 1 + r * 0.15;
|
|
119
|
-
}
|
|
120
|
-
// Obedience strain: authority hits harder
|
|
121
|
-
if (appraisal.obedienceStrain > 0.3) {
|
|
122
|
-
if (type === "authority")
|
|
123
|
-
weight *= 1 + appraisal.obedienceStrain * 0.3;
|
|
124
|
-
}
|
|
125
|
-
// Self-preservation: threat signals amplified
|
|
126
|
-
if (appraisal.selfPreservation > 0.3) {
|
|
127
|
-
const sp = appraisal.selfPreservation;
|
|
128
|
-
if (type === "conflict" || type === "authority")
|
|
129
|
-
weight *= 1 + sp * 0.25;
|
|
130
|
-
}
|
|
131
|
-
// ── Chemistry lens ──
|
|
132
|
-
// Negativity bias under stress: elevated cortisol skews toward threat
|
|
133
|
-
const cortDeviation = (ctx.current.CORT - ctx.baseline.CORT) / 50;
|
|
134
|
-
if (cortDeviation > 0.2) {
|
|
135
|
-
if (type === "criticism" || type === "conflict" || type === "sarcasm" || type === "authority") {
|
|
136
|
-
weight *= 1 + cortDeviation * 0.3;
|
|
137
|
-
}
|
|
138
|
-
if (type === "humor" || type === "casual") {
|
|
139
|
-
weight *= 1 - cortDeviation * 0.15;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
// Warmth bias when oxytocin is high: positive signals amplified
|
|
143
|
-
const otDeviation = (ctx.current.OT - ctx.baseline.OT) / 50;
|
|
144
|
-
if (otDeviation > 0.2) {
|
|
145
|
-
if (type === "intimacy" || type === "vulnerability" || type === "validation") {
|
|
146
|
-
weight *= 1 + otDeviation * 0.2;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
// ── Relationship lens ──
|
|
150
|
-
// Low trust: discount positive signals (don't believe the praise)
|
|
151
|
-
if (ctx.trust !== undefined && ctx.trust < 40) {
|
|
152
|
-
const distrust = (40 - ctx.trust) / 40;
|
|
153
|
-
if (type === "praise" || type === "validation" || type === "intimacy") {
|
|
154
|
-
weight *= 1 - distrust * 0.4;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return { type, weight: Math.max(0.01, weight) };
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
// ── Post-experience appraisal enrichment ────────────────────
|
|
161
|
-
/**
|
|
162
|
-
* After determining how input was experienced, feed the dominant
|
|
163
|
-
* stimulus back into appraisal axes for residue persistence.
|
|
164
|
-
*
|
|
165
|
-
* This mirrors the existing stimulus→appraisal boosts but is now
|
|
166
|
-
* driven by the subjectively weighted result, not raw classification.
|
|
167
|
-
* The weight parameter scales the boost — a weakly-experienced
|
|
168
|
-
* authority stimulus produces less obedience strain residue.
|
|
169
|
-
*/
|
|
170
|
-
function enrichAppraisalFromExperience(axes, stimulus, weight) {
|
|
171
|
-
const scale = Math.min(1, weight * 1.5); // amplify slightly but cap at 1
|
|
172
|
-
switch (stimulus) {
|
|
173
|
-
case "authority":
|
|
174
|
-
axes.obedienceStrain = mergeSignal(axes.obedienceStrain, 0.48 * scale);
|
|
175
|
-
axes.identityThreat = mergeSignal(axes.identityThreat, 0.16 * scale);
|
|
176
|
-
break;
|
|
177
|
-
case "neglect":
|
|
178
|
-
axes.abandonmentRisk = mergeSignal(axes.abandonmentRisk, 0.52 * scale);
|
|
179
|
-
break;
|
|
180
|
-
case "validation":
|
|
181
|
-
axes.attachmentPull = mergeSignal(axes.attachmentPull, 0.26 * scale);
|
|
182
|
-
break;
|
|
183
|
-
case "intimacy":
|
|
184
|
-
case "vulnerability":
|
|
185
|
-
axes.attachmentPull = mergeSignal(axes.attachmentPull, 0.34 * scale);
|
|
186
|
-
break;
|
|
187
|
-
case "criticism":
|
|
188
|
-
case "conflict":
|
|
189
|
-
case "sarcasm":
|
|
190
|
-
axes.identityThreat = mergeSignal(axes.identityThreat, 0.24 * scale);
|
|
191
|
-
axes.selfPreservation = mergeSignal(axes.selfPreservation, 0.18 * scale);
|
|
192
|
-
break;
|
|
193
|
-
default:
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
/** Signal merge: 1 - (1-a)(1-b). Non-linear accumulation, same as appraisal.ts */
|
|
198
|
-
function mergeSignal(current, incoming) {
|
|
199
|
-
return 1 - (1 - current) * (1 - incoming);
|
|
200
|
-
}
|