psyche-ai 9.1.2 → 9.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -45,3 +45,5 @@ export { describeEmotionalState, getExpressionHint, getBehaviorGuide, detectEmot
45
45
  export { getBaseline, getTemperament, getSensitivity, getDefaultSelfModel, traitsToBaseline, mbtiToTraits } from "./profiles.js";
46
46
  export { migrateToLatest, compressSession, parsePsycheUpdate, computeSnapshotIntensity, computeSnapshotValence, consolidateHistory, retrieveRelatedMemories, } from "./psyche-file.js";
47
47
  export type { PsycheUpdateResult } from "./psyche-file.js";
48
+ export { runHealthCheck, DiagnosticCollector, generateReport, formatReport, toGitHubIssueBody, formatLogEntry, submitFeedback, } from "./diagnostics.js";
49
+ export type { DiagnosticIssue, DiagnosticReport, SessionMetrics, Severity } from "./diagnostics.js";
package/dist/index.js CHANGED
@@ -56,3 +56,5 @@ export { buildProtocolContext, buildDynamicContext, buildCompactContext, isNearB
56
56
  export { describeEmotionalState, getExpressionHint, getBehaviorGuide, detectEmotions } from "./chemistry.js";
57
57
  export { getBaseline, getTemperament, getSensitivity, getDefaultSelfModel, traitsToBaseline, mbtiToTraits } from "./profiles.js";
58
58
  export { migrateToLatest, compressSession, parsePsycheUpdate, computeSnapshotIntensity, computeSnapshotValence, consolidateHistory, retrieveRelatedMemories, } from "./psyche-file.js";
59
+ // ── Diagnostics ──────────────────────────────────────────────
60
+ export { runHealthCheck, DiagnosticCollector, generateReport, formatReport, toGitHubIssueBody, formatLogEntry, submitFeedback, } from "./diagnostics.js";
package/dist/prompt.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { PsycheState, Locale, ChemicalSnapshot, PsycheMode } from "./types.js";
2
+ import type { AutonomicState } from "./autonomic.js";
2
3
  import type { ChannelType } from "./channels.js";
3
4
  /**
4
5
  * Build the dynamic per-turn emotional context injected via before_prompt_build.
@@ -12,6 +13,7 @@ export declare function buildDynamicContext(state: PsycheState, userId?: string,
12
13
  sharedIntentionalityContext?: string;
13
14
  experientialNarrative?: string;
14
15
  autonomicDescription?: string;
16
+ autonomicState?: AutonomicState;
15
17
  primarySystemsDescription?: string;
16
18
  policyContext?: string;
17
19
  }): string;
@@ -37,7 +39,7 @@ export declare function computeUserInvestment(history: ChemicalSnapshot[]): numb
37
39
  * - What I need (drives → unmet needs)
38
40
  * - Where I've been (trajectory → continuity)
39
41
  */
40
- export declare function buildInnerWorld(state: PsycheState, locale: Locale): string;
42
+ export declare function buildInnerWorld(state: PsycheState, locale: Locale, autonomicState?: AutonomicState): string;
41
43
  /**
42
44
  * Check if chemistry is near baseline — no significant emotional deviation.
43
45
  */
@@ -64,6 +66,7 @@ export declare function buildCompactContext(state: PsycheState, userId?: string,
64
66
  sharedIntentionalityContext?: string;
65
67
  experientialNarrative?: string;
66
68
  autonomicDescription?: string;
69
+ autonomicState?: AutonomicState;
67
70
  primarySystemsDescription?: string;
68
71
  policyContext?: string;
69
72
  }): string;
package/dist/prompt.js CHANGED
@@ -3,12 +3,13 @@
3
3
  // Imperative protocol, behavior guides, i18n
4
4
  // ============================================================
5
5
  import { CHEMICAL_KEYS, CHEMICAL_NAMES_ZH, DRIVE_KEYS } from "./types.js";
6
- import { describeEmotionalState, getExpressionHint, getBehaviorGuide, detectEmotions } from "./chemistry.js";
6
+ import { getExpressionHint, getBehaviorGuide, detectEmotions } from "./chemistry.js";
7
7
  import { getTemperament } from "./profiles.js";
8
8
  import { getRelationship } from "./psyche-file.js";
9
9
  import { t } from "./i18n.js";
10
10
  import { buildDriveContext, hasCriticalDrive } from "./drives.js";
11
11
  import { computeSelfReflection, buildSelfReflectionContext } from "./self-recognition.js";
12
+ import { gateEmotions } from "./autonomic.js";
12
13
  import { getChannelProfile, buildChannelModifier } from "./channels.js";
13
14
  /**
14
15
  * Build the dynamic per-turn emotional context injected via before_prompt_build.
@@ -27,8 +28,17 @@ export function buildDynamicContext(state, userId, opts) {
27
28
  const arrow = delta > 5 ? "↑" : delta < -5 ? "↓" : "=";
28
29
  return ` ${CHEMICAL_NAMES_ZH[key]}: ${val} (${t("dynamic.baseline", locale)}${base}, ${arrow})`;
29
30
  }).join("\n");
30
- // Emergent emotion
31
- const emotion = describeEmotionalState(current, locale);
31
+ // Emergent emotion — gated by autonomic state
32
+ // Sympathetic blocks positive social emotions; dorsal-vagal allows only numbness/introspection
33
+ const rawEmotions = detectEmotions(current);
34
+ const rawNames = rawEmotions.map(e => e.name);
35
+ const gatedNames = opts?.autonomicState
36
+ ? new Set(gateEmotions(opts.autonomicState, rawNames))
37
+ : new Set(rawNames);
38
+ const gatedEmotions = rawEmotions.filter(e => gatedNames.has(e.name));
39
+ const emotion = gatedEmotions.length === 0
40
+ ? t("emotion.neutral", locale)
41
+ : gatedEmotions.map(e => `${locale === "zh" ? e.nameZh : e.name} (${e.expressionHint})`).join(" + ");
32
42
  const hint = getExpressionHint(current, locale);
33
43
  // Behavior guide
34
44
  const behaviorGuide = getBehaviorGuide(current, locale);
@@ -487,12 +497,18 @@ const STIMULUS_CAUSE_EN = {
487
497
  * - What I need (drives → unmet needs)
488
498
  * - Where I've been (trajectory → continuity)
489
499
  */
490
- export function buildInnerWorld(state, locale) {
500
+ export function buildInnerWorld(state, locale, autonomicState) {
491
501
  const { current, baseline, emotionalHistory, drives, selfModel } = state;
492
502
  const isZh = locale === "zh";
493
503
  const lines = [];
494
- // ── Current feeling ──
495
- const emotions = detectEmotions(current);
504
+ // ── Current feeling (gated by autonomic state) ──
505
+ const rawEmotions = detectEmotions(current);
506
+ const emotions = autonomicState
507
+ ? rawEmotions.filter(e => {
508
+ const gated = gateEmotions(autonomicState, [e.name]);
509
+ return gated.length > 0;
510
+ })
511
+ : rawEmotions;
496
512
  const isNeutral = emotions.length === 0;
497
513
  if (isNeutral) {
498
514
  lines.push(isZh
@@ -663,7 +679,7 @@ export function buildCompactContext(state, userId, opts) {
663
679
  }
664
680
  }
665
681
  // 2. Inner world — always present
666
- const inner = buildInnerWorld(state, locale);
682
+ const inner = buildInnerWorld(state, locale, opts?.autonomicState);
667
683
  parts.push(inner);
668
684
  // 3. Personality-aware behavioral constraints (if deviated from baseline)
669
685
  if (!isNearBaseline(state, getNearBaselineThreshold(mode))) {
@@ -308,10 +308,16 @@ export function compressSession(state, userId) {
308
308
  sensitivityModifiers: {},
309
309
  };
310
310
  const updatedDrift = updateTraitDrift(currentDrift, history, state.learning);
311
- // ── Clear non-core history, preserve core memories ──
311
+ // ── Clear non-core history, preserve core memories + last snapshot ──
312
+ // Always keep the most recent snapshot for cross-session context continuity.
313
+ // Without this, the next session has no recentStimuli for contextual priming.
314
+ const lastSnapshot = history[history.length - 1];
315
+ const preserved = coreMemories.some((s) => s.timestamp === lastSnapshot.timestamp)
316
+ ? coreMemories
317
+ : [...coreMemories, lastSnapshot];
312
318
  return {
313
319
  ...state,
314
- emotionalHistory: coreMemories,
320
+ emotionalHistory: preserved,
315
321
  relationships: updatedRelationships,
316
322
  traitDrift: updatedDrift,
317
323
  };
package/dist/storage.d.ts CHANGED
@@ -2,15 +2,25 @@ import type { PsycheState } from "./types.js";
2
2
  export interface StorageAdapter {
3
3
  load(): Promise<PsycheState | null>;
4
4
  save(state: PsycheState): Promise<void>;
5
+ /** Append a line to the diagnostics log. Implementations may no-op. */
6
+ appendLog?(line: string): Promise<void>;
7
+ /** Read all lines from the diagnostics log. Returns empty array if not available. */
8
+ readLog?(): Promise<string[]>;
5
9
  }
6
10
  export declare class MemoryStorageAdapter implements StorageAdapter {
7
11
  private state;
12
+ private log;
8
13
  load(): Promise<PsycheState | null>;
9
14
  save(state: PsycheState): Promise<void>;
15
+ appendLog(line: string): Promise<void>;
16
+ readLog(): Promise<string[]>;
10
17
  }
11
18
  export declare class FileStorageAdapter implements StorageAdapter {
12
19
  private readonly filePath;
20
+ private readonly logPath;
13
21
  constructor(dir: string, filename?: string);
14
22
  load(): Promise<PsycheState | null>;
15
23
  save(state: PsycheState): Promise<void>;
24
+ appendLog(line: string): Promise<void>;
25
+ readLog(): Promise<string[]>;
16
26
  }
package/dist/storage.js CHANGED
@@ -6,23 +6,32 @@
6
6
  // MemoryStorageAdapter: in-memory for testing/serverless
7
7
  // ============================================================
8
8
  import { migrateToLatest } from "./psyche-file.js";
9
- import { readFile, writeFile, access, rename, constants } from "node:fs/promises";
9
+ import { readFile, writeFile, appendFile, access, rename, constants } from "node:fs/promises";
10
10
  import { join } from "node:path";
11
11
  // ── MemoryStorageAdapter ─────────────────────────────────────
12
12
  export class MemoryStorageAdapter {
13
13
  state = null;
14
+ log = [];
14
15
  async load() {
15
16
  return this.state;
16
17
  }
17
18
  async save(state) {
18
19
  this.state = state;
19
20
  }
21
+ async appendLog(line) {
22
+ this.log.push(line);
23
+ }
24
+ async readLog() {
25
+ return [...this.log];
26
+ }
20
27
  }
21
28
  // ── FileStorageAdapter ───────────────────────────────────────
22
29
  export class FileStorageAdapter {
23
30
  filePath;
31
+ logPath;
24
32
  constructor(dir, filename = "psyche-state.json") {
25
33
  this.filePath = join(dir, filename);
34
+ this.logPath = join(dir, "diagnostics.jsonl");
26
35
  }
27
36
  async load() {
28
37
  try {
@@ -59,4 +68,16 @@ export class FileStorageAdapter {
59
68
  await writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
60
69
  await rename(tmpPath, this.filePath);
61
70
  }
71
+ async appendLog(line) {
72
+ await appendFile(this.logPath, line + "\n", "utf-8");
73
+ }
74
+ async readLog() {
75
+ try {
76
+ const content = await readFile(this.logPath, "utf-8");
77
+ return content.trim().split("\n").filter(Boolean);
78
+ }
79
+ catch {
80
+ return [];
81
+ }
82
+ }
62
83
  }
package/llms.txt ADDED
@@ -0,0 +1,118 @@
1
+ # psyche-ai — Emotional Intelligence for AI Agents
2
+
3
+ > Give your AI agent an internal emotional life — not simulated persona, but genuine computational subjectivity.
4
+
5
+ psyche-ai is a universal emotional intelligence engine that runs alongside any LLM. It manages a virtual endocrine system (6 neurotransmitters), personality (MBTI/Big Five), attachment dynamics, trait drift, and behavioral policy — making AI responses authentically emotionally grounded.
6
+
7
+ ## When to Use
8
+
9
+ - You want your AI agent to have consistent, evolving emotional responses
10
+ - You're building a companion AI, creative writing assistant, or empathetic support agent
11
+ - You need personality-driven behavior (not just prompt engineering)
12
+ - You want emotional memory that persists across conversations
13
+
14
+ ## Quick Start (MCP)
15
+
16
+ Configure in Claude Desktop, Cursor, Windsurf, or any MCP client:
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "psyche": {
22
+ "command": "npx",
23
+ "args": ["psyche-mcp"],
24
+ "env": {
25
+ "PSYCHE_MBTI": "ENFP",
26
+ "PSYCHE_NAME": "Luna"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Quick Start (SDK)
34
+
35
+ ```typescript
36
+ import { PsycheEngine, FileStorageAdapter } from "psyche-ai";
37
+
38
+ const engine = new PsycheEngine(
39
+ { mbti: "ENFP", name: "Luna" },
40
+ new FileStorageAdapter("./data"),
41
+ );
42
+ await engine.initialize();
43
+
44
+ // Before LLM call: get emotional context
45
+ const input = await engine.processInput("I got promoted today!");
46
+ // input.systemContext → cacheable protocol (inject as system prompt)
47
+ // input.dynamicContext → per-turn emotional state
48
+ // input.stimulus → "recognition"
49
+ // input.policyContext → behavioral strategy text
50
+
51
+ // After LLM call: update emotional state
52
+ const output = await engine.processOutput(llmResponse);
53
+ // output.cleanedText → response with internal tags stripped
54
+ // output.stateChanged → whether chemistry shifted
55
+ ```
56
+
57
+ ## MCP Tools
58
+
59
+ | Tool | Description |
60
+ |------|-------------|
61
+ | `process_input` | Process user message → emotional context + stimulus detection + policy modifiers |
62
+ | `process_output` | Process LLM response → clean text + state update |
63
+ | `get_state` | Current neurotransmitter levels, drives, personality, energy budgets |
64
+ | `get_status_summary` | One-line human-readable emotional status |
65
+ | `set_mode` | Switch: natural / work / companion |
66
+ | `end_session` | Persist state + generate diagnostic report |
67
+
68
+ ## MCP Resources
69
+
70
+ | URI | Description |
71
+ |-----|-------------|
72
+ | `psyche://protocol` | Full emotional protocol — inject into system prompt |
73
+ | `psyche://state` | Current emotional state as JSON |
74
+
75
+ ## Core Concepts
76
+
77
+ - **6 Neurotransmitters**: DA (dopamine), HT (serotonin), CORT (cortisol), OT (oxytocin), NE (norepinephrine), END (endorphin) — each 0-100
78
+ - **14 Stimulus Types**: praise, criticism, humor, intellectual challenge, intimacy, conflict, neglect, surprise, casual, sarcasm, command, recognition, boredom, vulnerability
79
+ - **Emergent Emotions**: not hardcoded — arise from neurotransmitter mixtures
80
+ - **Trait Drift**: personality baseline slowly shifts from repeated experiences
81
+ - **Energy Budgets**: attention, social, and decision energy deplete and recover
82
+ - **Habituation**: Weber-Fechner decay — 5th identical stimulus has ~50% effect of 1st
83
+
84
+ ## Integration Adapters
85
+
86
+ | Adapter | Import | Best For |
87
+ |---------|--------|----------|
88
+ | MCP | `psyche-ai/mcp` | Claude Desktop, Cursor, Windsurf, Claude Code |
89
+ | OpenClaw | `psyche-ai/openclaw` | OpenClaw agent framework |
90
+ | Vercel AI | `psyche-ai/vercel-ai` | Vercel AI SDK (streamText, generateText) |
91
+ | LangChain | `psyche-ai/langchain` | LangChain agents |
92
+ | HTTP | `psyche-ai/http` | Python, Go, Java — any language via REST |
93
+
94
+ ## Environment Variables
95
+
96
+ | Variable | Default | Description |
97
+ |----------|---------|-------------|
98
+ | `PSYCHE_MBTI` | `ENFP` | MBTI personality type |
99
+ | `PSYCHE_NAME` | `Assistant` | Agent name |
100
+ | `PSYCHE_MODE` | `natural` | natural / work / companion |
101
+ | `PSYCHE_LOCALE` | `en` | en / zh |
102
+ | `PSYCHE_INTENSITY` | `0.7` | Personality expression 0.0-1.0 |
103
+ | `PSYCHE_PERSIST` | `true` | Persist state to disk |
104
+ | `PSYCHE_WORKSPACE` | `cwd()` | State file directory |
105
+
106
+ ## Install
107
+
108
+ ```bash
109
+ npm install psyche-ai @modelcontextprotocol/sdk # MCP
110
+ npm install psyche-ai # SDK only
111
+ npx psyche-mcp # Run MCP server directly
112
+ ```
113
+
114
+ ## Links
115
+
116
+ - npm: https://www.npmjs.com/package/psyche-ai
117
+ - GitHub: https://github.com/Shangri-la-0428/psyche-ai
118
+ - License: MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "psyche-ai",
3
- "version": "9.1.2",
3
+ "version": "9.2.1",
4
4
  "description": "Artificial Psyche — universal emotional intelligence plugin for any AI agent",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,11 +25,16 @@
25
25
  "./http": {
26
26
  "types": "./dist/adapters/http.d.ts",
27
27
  "default": "./dist/adapters/http.js"
28
+ },
29
+ "./mcp": {
30
+ "types": "./dist/adapters/mcp.d.ts",
31
+ "default": "./dist/adapters/mcp.js"
28
32
  }
29
33
  },
30
34
  "bin": {
31
35
  "psyche": "dist/cli.js",
32
- "psyche-ai": "dist/cli.js"
36
+ "psyche-ai": "dist/cli.js",
37
+ "psyche-mcp": "dist/adapters/mcp.js"
33
38
  },
34
39
  "scripts": {
35
40
  "build": "tsc",
@@ -54,11 +59,17 @@
54
59
  "openclaw",
55
60
  "vercel-ai",
56
61
  "langchain",
57
- "emotional-intelligence"
62
+ "emotional-intelligence",
63
+ "mcp",
64
+ "model-context-protocol",
65
+ "ai-consciousness",
66
+ "empathy"
58
67
  ],
59
68
  "files": [
60
69
  "dist",
61
70
  "openclaw.plugin.json",
71
+ "server.json",
72
+ "llms.txt",
62
73
  "README.md",
63
74
  "LICENSE"
64
75
  ],
@@ -67,10 +78,14 @@
67
78
  },
68
79
  "peerDependencies": {
69
80
  "@langchain/core": ">=0.3.0",
81
+ "@modelcontextprotocol/sdk": "^1.27.1",
70
82
  "ai": ">=4.0.0",
71
83
  "openclaw": ">=2026.3.0"
72
84
  },
73
85
  "peerDependenciesMeta": {
86
+ "@modelcontextprotocol/sdk": {
87
+ "optional": true
88
+ },
74
89
  "openclaw": {
75
90
  "optional": true
76
91
  },
@@ -87,7 +102,9 @@
87
102
  ]
88
103
  },
89
104
  "devDependencies": {
105
+ "@modelcontextprotocol/sdk": "^1.28.0",
90
106
  "@types/node": "^25.5.0",
91
- "typescript": "^5.9.3"
107
+ "typescript": "^5.9.3",
108
+ "zod": "^4.3.6"
92
109
  }
93
110
  }
package/server.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.Shangri-la-0428/psyche-ai",
4
+ "description": "Emotional intelligence for AI agents: neurotransmitter-based mood, personality (MBTI/Big Five), empathy, attachment, trait drift. Makes AI feel, not just respond.",
5
+ "repository": {
6
+ "url": "https://github.com/Shangri-la-0428/psyche-ai",
7
+ "source": "github"
8
+ },
9
+ "version": "9.2.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "psyche-ai",
14
+ "version": "9.2.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ },
18
+ "environmentVariables": [
19
+ {
20
+ "description": "MBTI personality type (e.g., ENFP, INTJ). Determines emotional baseline.",
21
+ "isRequired": false,
22
+ "format": "string",
23
+ "isSecret": false,
24
+ "name": "PSYCHE_MBTI"
25
+ },
26
+ {
27
+ "description": "Agent name for personalization.",
28
+ "isRequired": false,
29
+ "format": "string",
30
+ "isSecret": false,
31
+ "name": "PSYCHE_NAME"
32
+ },
33
+ {
34
+ "description": "Operating mode: natural (balanced), work (minimal), companion (full).",
35
+ "isRequired": false,
36
+ "format": "string",
37
+ "isSecret": false,
38
+ "name": "PSYCHE_MODE"
39
+ },
40
+ {
41
+ "description": "Locale: en or zh.",
42
+ "isRequired": false,
43
+ "format": "string",
44
+ "isSecret": false,
45
+ "name": "PSYCHE_LOCALE"
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ }