{"_id":"@clarashafiq/jiwen","_rev":"4-26ea4f7adf44d373f18da6f2b49081dc","name":"@clarashafiq/jiwen","dist-tags":{"latest":"0.4.0"},"versions":{"0.3.0":{"name":"@clarashafiq/jiwen","version":"0.3.0","keywords":["ai-companion","virtual-pet","emotion-engine","continuous-state","homeostasis","ai-character","npc-ai","affective-computing","simulation"],"license":"MIT","_id":"@clarashafiq/jiwen@0.3.0","maintainers":[{"name":"clarashafiq","email":"kekewei0821@gmail.com"}],"homepage":"https://github.com/kekewei0821-bot/jiwen#readme","bugs":{"url":"https://github.com/kekewei0821-bot/jiwen/issues"},"dist":{"shasum":"c4194c5e1bd9326a2d5ad7e1c2e0e5de91ef0525","tarball":"https://registry.npmjs.org/@clarashafiq/jiwen/-/jiwen-0.3.0.tgz","fileCount":8,"integrity":"sha512-EOj0bnSKab2S6BPvBHCa76pmxtZppIX2bRZevxE0lO5Mo6fIcQu+aNN62+aPRv3RxEvRZIUOR/vOX9cwU4KHJQ==","signatures":[{"sig":"MEUCIDlHELoXn0GOO5qEfRN9TCez3UfKCFCCmCRWHcVUwviuAiEA5HNMWTKA/zHMohbN8aTBhRt/Fj9pTVAq/Gkb2fM8gZs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104502},"main":"jiwen.js","gitHead":"e77855d1f48d2832e12f4e4c6ca0d15ca390179c","_npmUser":{"name":"clarashafiq","email":"kekewei0821@gmail.com"},"repository":{"url":"git+https://github.com/kekewei0821-bot/jiwen.git","type":"git"},"_npmVersion":"10.8.2","description":"积温 — 不靠概率骰子的 AI 角色主动意识引擎。五轴连续状态 + 数学漂移 + 阈值触发 + 参数模拟器","directories":{},"_nodeVersion":"18.20.8","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jiwen_0.3.0_1782495092993_0.5266100126145996","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@clarashafiq/jiwen","version":"0.3.1","keywords":["ai-companion","virtual-pet","emotion-engine","continuous-state","homeostasis","ai-character","npc-ai","affective-computing","simulation"],"license":"MIT","_id":"@clarashafiq/jiwen@0.3.1","maintainers":[{"name":"clarashafiq","email":"kekewei0821@gmail.com"}],"homepage":"https://github.com/ClaraShafiq/jiwen#readme","bugs":{"url":"https://github.com/ClaraShafiq/jiwen/issues"},"dist":{"shasum":"69be445cf8d0b1eebedaebb56dfa606dd8eea7a0","tarball":"https://registry.npmjs.org/@clarashafiq/jiwen/-/jiwen-0.3.1.tgz","fileCount":8,"integrity":"sha512-Q8H1fEs2ii8Vdy06AUSUj+ZSPL5RVrrnnGbuGFyVxYj2WWvLnwICrTHzkny0aTc6CPUWPElgQLmkYHISRJDjYQ==","signatures":[{"sig":"MEUCIQDV/AZ22H5E4Rlbtp5+zfb44xFsnwbBX1HnqnLJDfBZxgIgAdp7TxVMfOsHJSKWtykpbtDrDl/UZaeuznwKL5XArTY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104610},"main":"jiwen.js","gitHead":"f2dc64a3eeebf436e061ad740c4c694cb9dd7eec","_npmUser":{"name":"clarashafiq","email":"kekewei0821@gmail.com"},"repository":{"url":"git+https://github.com/ClaraShafiq/jiwen.git","type":"git"},"_npmVersion":"10.8.2","description":"积温 — 不靠概率骰子的 AI 角色主动意识引擎。五轴连续状态 + 数学漂移 + 阈值触发 + 参数模拟器","directories":{},"_nodeVersion":"18.20.8","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jiwen_0.3.1_1782495122993_0.7759946620636788","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@clarashafiq/jiwen","version":"0.3.2","keywords":["ai-companion","virtual-pet","emotion-engine","continuous-state","homeostasis","ai-character","npc-ai","affective-computing","simulation"],"license":"MIT","_id":"@clarashafiq/jiwen@0.3.2","maintainers":[{"name":"clarashafiq","email":"kekewei0821@gmail.com"}],"homepage":"https://github.com/ClaraShafiq/jiwen#readme","bugs":{"url":"https://github.com/ClaraShafiq/jiwen/issues"},"dist":{"shasum":"f93c9be18c4b805249938437215d2d83894989e4","tarball":"https://registry.npmjs.org/@clarashafiq/jiwen/-/jiwen-0.3.2.tgz","fileCount":8,"integrity":"sha512-nBiI/oJ7Xys6VIzyCo1kqF2vGDwdZ2gJm+EFV/WKiQtqEXZbUP5vFqz2YffMw1mb/fcjfA8Vmz0VsQCQ9J9OyA==","signatures":[{"sig":"MEUCIFFXpWuGQuhFwcnLqzH08eZCekBr4F+T4kcZm2jXlIhMAiEAkf5dDzN1G/KKoat7xeqnmH4eyMjek3J/FJY6Gwb5uU0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":107714},"main":"jiwen.js","gitHead":"32da7f826629290b6045b04dfbe58c4d0e11463c","_npmUser":{"name":"clarashafiq","email":"kekewei0821@gmail.com"},"repository":{"url":"git+https://github.com/ClaraShafiq/jiwen.git","type":"git"},"_npmVersion":"10.8.2","description":"积温 — 不靠概率骰子的 AI 角色主动意识引擎。五轴连续状态 + 数学漂移 + 阈值触发 + 参数模拟器","directories":{},"_nodeVersion":"18.20.8","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jiwen_0.3.2_1782497323748_0.0594046048336514","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@clarashafiq/jiwen","version":"0.4.0","description":"积温 — 不靠概率骰子的 AI 角色主动意识引擎。五轴连续状态 + 数学漂移 + 阈值触发 + 参数模拟器","main":"jiwen.js","license":"MIT","keywords":["ai-companion","virtual-pet","emotion-engine","continuous-state","homeostasis","ai-character","npc-ai","affective-computing","simulation"],"repository":{"type":"git","url":"git+https://github.com/ClaraShafiq/jiwen.git"},"_id":"@clarashafiq/jiwen@0.4.0","gitHead":"38acf8e18996861c816b93b0938ac686dcc66337","bugs":{"url":"https://github.com/ClaraShafiq/jiwen/issues"},"homepage":"https://github.com/ClaraShafiq/jiwen#readme","_nodeVersion":"18.20.8","_npmVersion":"10.8.2","dist":{"integrity":"sha512-/fREMh2W7RPeUfMCcsIWAfpbmPgpBBHy6ynTYi5phZxV+RxU3Du56pwHCnRWn7evzMs+mc1iSoMzzDgOvOSrQw==","shasum":"149b8eda73bfca3f49f1f10eae90bb435c35cf59","tarball":"https://registry.npmjs.org/@clarashafiq/jiwen/-/jiwen-0.4.0.tgz","fileCount":8,"unpackedSize":107691,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCQyos/Y5BwKdzXDRj4IyNdcLphgpfkKfEXtftq+BMfvwIhAOrLxV1py7tRH33ctpX1QL35ET7nh9MzaaRb/2xIBsN7"}]},"_npmUser":{"name":"clarashafiq","email":"kekewei0821@gmail.com"},"directories":{},"maintainers":[{"name":"clarashafiq","email":"kekewei0821@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jiwen_0.4.0_1782497666107_0.5415328934040664"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-26T17:31:32.731Z","modified":"2026-06-26T18:14:26.345Z","0.3.0":"2026-06-26T17:31:33.139Z","0.3.1":"2026-06-26T17:32:03.234Z","0.3.2":"2026-06-26T18:08:43.916Z","0.4.0":"2026-06-26T18:14:26.253Z"},"bugs":{"url":"https://github.com/ClaraShafiq/jiwen/issues"},"license":"MIT","homepage":"https://github.com/ClaraShafiq/jiwen#readme","keywords":["ai-companion","virtual-pet","emotion-engine","continuous-state","homeostasis","ai-character","npc-ai","affective-computing","simulation"],"repository":{"type":"git","url":"git+https://github.com/ClaraShafiq/jiwen.git"},"description":"积温 — 不靠概率骰子的 AI 角色主动意识引擎。五轴连续状态 + 数学漂移 + 阈值触发 + 参数模拟器","maintainers":[{"name":"clarashafiq","email":"kekewei0821@gmail.com"}],"readme":"# 积温 — 不靠概率骰子的 AI 角色主动意识引擎\n\n> AI 角色只会在你发消息之后回复——它从来不会先开口。因为没人告诉它「什么时候该说话」。\n>\n> 积温做这件事。它在后台持续追踪五个数值：**想不想找你、嘴硬不硬、心情好坏、焦不焦躁、手头有没有事做。** 数值随时间漂移，到了阈值自然触发行为。不靠随机数，不靠 prompt engineering。\n>\n> 一个 ~500 行的 JS 函数，零依赖。你把它挂到自己的项目里，每几分钟调一次 `tick()`。它不写回复、不存数据、不调模型——只输出状态和触发信号。剩下的你自己来。\n\n## 这是什么\n\n- **`createJiwen(opts)`** — 创建一个角色实例。你告诉它怎么读消息、怎么存状态、各轴速率多少，它把剩下的事干了\n- **`tick(minutes)`** — 每几分钟调一次。传入经过的分钟数，返回触发动作数组：`contact`（开口）、`find_activity`（逃避/自我调节）、`observation`（注意到沉默但还没想动）\n- **`getPromptContext()` / `getStyleGuidance()`** — 把数值翻译成人话，塞进 LLM prompt。模型不需要知道 `connection=0.47`，只需要知道「你很别扭，想找她又拉不下脸」\n- **`simulate.js`** — 写一条事件线，跑多组参数，出 CSV 轨迹对比。调参用的\n- **`node jiwen.test.js`** — 29 项测试，改完跑一下\n\n## 为什么不用概率骰子\n\n每 N 分钟 roll 一次，沉默越久概率越高——这是最常见的做法。问题是它不可控：两小时沉默可能只是因为骰子连续没中。角色不是在「想不想说话」，而是在「有没有被骰中」。\n\n积温用五个连续数值替代概率。数值随时间漂移，互相制衡，到阈值自然触发。想找她又嘴硬？两股力同时在跑，强的那方决定行为。结果是确定性的——同样的状态输入，同样的行为输出。\n\n## 五轴状态\n\n五个连续数值在后台漂移。这些维度是从一个嘴硬又骄傲的角色身上推出来的——换一个角色，核心矛盾不同，维度可以增减。\n\n| 轴 | 范围 | 含义 |\n|---|------|------|\n| **连接需求** connection | 0 → 1 | 多久没听到对方了？想念在累积 |\n| **骄傲** pride | -1 → +1 | 端着还是放软 |\n| **愉悦度** valence | -1 → +1 | 好受还是难受（Russell 环状模型） |\n| **唤醒度** arousal | -1 → +1 | 焦躁/兴奋还是平静/慵懒（正交于 valence） |\n| **沉浸度** immersion | 0 → 1 | 正在做某件事的专注程度，也是骄傲的缓冲垫 |\n\nValence 和 Arousal 来自 Russell (1980) 情绪环状模型——两根正交轴构成一个情绪平面。愤怒（低 valence + 高 arousal）和悲伤（低 valence + 低 arousal）落在不同位置，行为表现完全不同。\n\n轴之间互相制衡：\n\n- 连接需求触达开口阈值，但骄傲高 → 不开口，找事做（沉浸度充当面子的缓冲）\n- 低 valence + 高 arousal → 烦躁带刺；低 valence + 低 arousal → 低落话少\n- 等待拉升 arousal，同时锁定 valence 回归（想念越重，坏情绪越难消散）\n- 沉浸度衰减 → 不能永远躲在书后面，借口会过期\n\n## 数学漂移与阈值\n\n**数值在后台一直算着，不需要调用任何 AI 模型。**\n\n### 漂移 / 衰减\n\n| 轴 | 行为 | 速率 |\n|---|------|------|\n| 连接需求 | 分段增长 | 由 `connectionRateFn` 动态决定基础速率；前 `accelDelay` 分钟线性增长，之后叠加加速度 `pow(1+c, connectionAccel)`；valence 状态可进一步调制 |\n| 骄傲 | 受连接需求驱动 | 未触发防御时回归 0（0.003/min）；被冷落时防御性上升至 `prideDefendTarget` |\n| Valence | 回归设定点，等待时锁定 | 默认回归 0（0.005/min）；connection 超过 `valenceLockThreshold` 时回归速率降至 `valenceLockFactor` 倍 |\n| Arousal | 平时回归平静，等待时攀升 | 默认回归 0（0.005/min）；connection 超过 `arousalConnectionRiseThreshold` 时以 `arousalConnectionRiseRate` 向上攀升 |\n| 沉浸度 | 线性衰减 | 0.01/min（60 分钟后归零）；`setActivity()` 可部分缓解连接需求 |\n\n### 连接需求增长曲线\n\n```\nconnection 增长 = baseRate × accelFactor × valenceFactor\n\nbaseRate      ← connectionRateFn(lastMessage)  — 对方最后说了什么（晚安→慢，中断→快）\naccelFactor   ← 前 accelDelay 分钟为 1.0（线性），之后为 pow(1+c, connectionAccel)\nvalenceFactor ← 开心/中性 → 1.0 | 轻度不开心 → boost | 严重低落 → dampen\n```\n\n三层叠加：对方说了晚安 → 涨得慢；突然中断 → 涨得快。等了半小时没动静 → 开始加速。轻度不开心想求安慰 → 加速；严重低落自我封闭 → 减速。\n\n### 阈值触发\n\n```\nconnection >= 0.20   开始注意到沉默 → observation（不发出，内心念头）\nconnection >= 0.35   考虑开口\n    pride >= 0.5 → find_activity（找事做，不开口）\n    pride < 0.5  → contact（开口）\nconnection >= 0.50   强制 contact，不管骄傲多高\n\nvalence <= valenceActivity    心情差 → find_activity（自我调节）\narousal >= arousalAgitation   太焦躁 → find_activity（宣泄多余唤醒）\n```\n\n**积累 → 犹豫 → 撑不住。** 数值根据角色性格校准——更粘人的角色可以去掉骄傲阻断、压低强制触发线。\n\n### 参数表\n\n所有耦合参数默认关闭（设为 0 或不可能触达的阈值 1.0），向后兼容。按需开启。\n\n| 参数 | 作用 |\n|------|------|\n| `connectionAccel` | 非线性加速指数（0=纯线性） |\n| `accelDelay` | 加速前的线性缓冲（分钟） |\n| `valenceSetpoint` | Valence 回归目标（0=中性，负=偏冷） |\n| `valenceConnectBoost / Threshold` | 轻度不开心时 connection 增长倍率 |\n| `valenceConnectDampen / Threshold` | 严重低落时 connection 增长倍率 |\n| `valenceLockThreshold / Factor` | 想念强烈时坏情绪回归减速 |\n| `arousalConnectionRiseThreshold / Rate` | 等待让 arousal 攀升 |\n| `prideDefendThreshold / Target / Rate` | 被冷落时骄傲防御性升高 |\n| `prideArousalConflictRate` | 想要又端着 → 内心战争加热 arousal |\n| `prideErosionRate` | 想念太重 → pride 被迫下降 |\n| `activityConnectionRelief` | 做事情缓解连接需求的幅度 |\n\n## 三层成本模型\n\n| 层级 | 做什么 | 模型 | 频率 |\n|------|--------|------|------|\n| **数学漂移** | 五轴数值随时间变化 | 不需要 | 每 5 分钟 |\n| **对话分析** | 读对话段，提取情绪 delta | 轻量模型 | 有新对话时 |\n| **行动生成** | 生成开口内容 / 行为 | 大模型 | 阈值触发时 |\n\n对话分析用轻量模型（如 DeepSeek V4 Flash），只返回几个 delta 值：\n\n```json\n{ \"pride\": -0.1, \"valence\": +0.2, \"arousal\": -0.05, \"connection\": -0.15 }\n```\n\n被夸了 pride 降，聊开心了 valence 涨，放松了 arousal 降，说完了想说的 connection 降。\n\n## 把数字变成人话\n\n数值不直接喂给 LLM。`getPromptContext()` 和 `getStyleGuidance()` 把状态翻译成自然语言注入 prompt。\n\n**状态描述**（角色视角）：\n```\nUser 好一阵子没说话了。开始在想 User 在干嘛。\n有一点端着，但也不是不能开口。\n刚才在看书，脑子里还有些书里的东西。\n```\n\n**风格指引**（状态到语气的映射）：\n```\n骄傲 > 0.5：嘴硬。不承认在等。必须找借口开口。\n连接需求 > 0.4 且骄傲 > 0.4：别扭，想找她又拉不下脸。话里带赌气的味道。\n情绪 < -0.3：心情不太好。能用句号就别用逗号。\n强制触发（connection >= 0.5）：坐不住了。可能直接说——「人呢？」\n```\n\n对话情绪变化用外部观察者模式判断：调一个轻量 LLM 做旁观分析，角色本身不分析自己——自我分析容易出戏，旁观者更准。\n\n## 在线演示\n\n[在线体验 →](https://clarashafiq.github.io/jiwen/)\n\n## 安装\n\n```bash\nnpm install @clarashafiq/jiwen\n```\n\n零外部依赖。纯 JavaScript。\n\n## 快速开始\n\n```js\nconst { createJiwen } = require('@clarashafiq/jiwen');\n\nconst jiwen = createJiwen({\n  // ── 消息源（必填）──\n  getLastMessage: () => {\n    return { id: 42, content: '晚安，去睡了', timestamp: '...' };\n  },\n\n  // ── 连接需求增长速率（必填）──\n  connectionRateFn: (lastMsg) => {\n    if (!lastMsg) return 0.0007;\n    if (lastMsg.content.includes('晚安')) return 0.0003;\n    if (lastMsg.content.includes('出门')) return 0.0005;\n    if (lastMsg.content.length < 10) return 0.0010;\n    return 0.0007;\n  },\n\n  // ── 持久化（可选但推荐）──\n  onSave: async (state) => {\n    await db.set('jiwen_state', JSON.stringify(state));\n  },\n  onLoad: async () => {\n    const raw = await db.get('jiwen_state');\n    return raw ? JSON.parse(raw) : null;\n  },\n});\n\n// ── 每 N 分钟 tick 一次 ──\nasync function heartbeat(minutesSinceLastTick) {\n  const triggers = await jiwen.tick(minutesSinceLastTick);\n\n  for (const t of triggers) {\n    if (t.action === 'contact') {\n      const ctx = jiwen.getPromptContext();\n      const style = jiwen.getStyleGuidance();\n      // 把 ctx 和 style 注入 LLM prompt，生成开口内容...\n      // 注意：connection 在这里不归零——开口不等于被回复。\n      // 部分缓解即可，等对方真正回应了再调 resetConnection()。\n      await jiwen.applyDelta({ connection: -0.35 });\n    }\n    if (t.action === 'find_activity') {\n      await jiwen.setActivity('search', 'AI最新动态');\n    }\n  }\n}\n\n// ── 聊天后应用情绪变化 ──\n// 对方回复了 → 分析情绪 delta → 连接需求归零\nawait jiwen.applyDelta({ pride: -0.1, valence: +0.05, connection: -0.3 });\nawait jiwen.resetConnection();\n\n// ── 查状态 ──\nconst state = await jiwen.getState();\n// { connection: 0, pride: 0.05, valence: 0.05, arousal: 0, immersion: 0, ... }\n```\n\n## API\n\n### `createJiwen(opts)`\n\n返回引擎实例。详见 [jiwen.js 顶部注释](./jiwen.js)。\n\n| 方法 | 说明 |\n|------|------|\n| `tick(minutes)` | 推进状态漂移，返回触发数组 |\n| `applyDelta({ pride?, valence?, arousal?, connection? })` | 叠加情绪变化（仍接受 `mood` → 映射到 `valence`） |\n| `getState()` | 获取完整状态快照 |\n| `getPromptContext()` | 生成 LLM 用的状态自然语言描述 |\n| `getStyleGuidance()` | 生成 LLM 用的说话风格指引 |\n| `resetConnection()` | 连接需求归零（对方回复后调用，不是开口后） |\n| `setActivity(type, label)` | 设置沉浸度（reading / search / browse / observe） |\n| `checkThresholds()` | 只检查阈值，不推进状态 |\n| `setLastChatMessageId(id)` | 标记已分析到的消息 ID |\n| `getLastChatMessageId()` | 获取上次分析到的消息 ID |\n| `setUserStatus(status)` | 设置对方状态（active / busy / away / sleeping） |\n| `getUserStatus()` | 获取对方当前状态 |\n| `getStateSummary()` | 返回当前状态的可读摘要（一行字符串，调试用） |\n\n### 调试日志\n\njiwen 默认只在**阈值触发时**打印状态。开启 `verbose` 后每次 `tick()` 都打印：\n\n```js\nconst jiwen = createJiwen({\n  verbose: true,  // 每次 tick 都打日志\n  // ...\n});\n```\n\n日志格式：\n```\n[积温] tick 5min | c:0.15→0.18 p:0.40→0.39 v:0.20→0.18 a:-0.10→-0.08 i:0.50 | 速率:0.0035/min | 触发: —\n```\n\n如果不想用 `console.log`（比如在 AstrBot 里需要把日志发到聊天窗口），传入 `onLog` 回调：\n\n```js\nconst jiwen = createJiwen({\n  onLog: (msg) => { /* 发到聊天 / 写文件 / 推通知 */ },\n  // ...\n});\n```\n\n`getStateSummary()` 返回一行紧凑的可读摘要，适合调试时快速查看：\n\n```js\nconsole.log(jiwen.getStateSummary());\n// [积温] c:0.15(悠闲) p:0.40(端着) v:0.20(中性) a:-0.10(平静) i:0.50(沉浸于reading) | userStatus: active\n```\n\n### 语调网格（推荐）\n\n手动写 `getPromptContext` / `getStyleGuidance` 查表函数比较繁琐。jiwen 提供了 `tone-grid` 模块——一个预置的 **9 情绪簇 × 5 档 pride** 语调网格，你只需要替换文案：\n\n```js\nconst { createJiwen } = require('@clarashafiq/jiwen');\nconst { createToneGrid } = require('@clarashafiq/jiwen/tone-grid');\n\n// 用默认通用文案（功能性的，但缺少角色个性）\nconst grid = createToneGrid();\n\n// 或者从 JSON 配置文件加载自定义文案：\n// const config = require('./my-character-tone.json');\n// const grid = createToneGrid(config);\n\nconst jiwen = createJiwen({\n  // ...其他配置,\n  getStyleGuidance: (state) => grid.getStyleGuidance(state),\n  getPromptContext:  (state) => grid.getPromptContext(state),\n});\n```\n\n**配置文件格式** (`my-character-tone.json`)：\n```json\n{\n  \"profiles\": {\n    \"excited\": {\n      \"1\": [\"完全放开了，话多且直接……\"],\n      \"2\": [\"语气轻快，带着笑意……\"],\n      \"3\": [\"心情不错但保持得体……\"],\n      \"4\": [\"表面克制但兴奋漏出来……\"],\n      \"5\": [\"即使开心也几乎不表现……\"]\n    },\n    \"content\": { ... },\n    \"agitated\": { ... },\n    \"depressed\": { ... },\n    \"neutral\": { ... },\n    \"sullen\": { ... },\n    \"restless\": { ... },\n    \"pleased\": { ... },\n    \"calm\": { ... }\n  },\n  \"urgencyBoost\": {\n    \"desperate\": { \"proactive\": \"...\", \"reactive\": \"...\" },\n    \"urgent\":    { \"proactive\": \"...\", \"reactive\": \"...\" },\n    \"aware\":     { \"proactive\": \"...\", \"reactive\": \"...\" }\n  }\n}\n```\n\n9 个情绪簇由 valence × arousal 二维象限 + 单轴极端情况 + 中性组成。每个簇 5 档 pride（1=完全不端着 → 5=全副武装）。`connection` 急迫度叠加在核心规则之上，区分「角色主动开口」(proactive) 和「回复对方」(reactive) 两种模式。\n\n**只覆盖部分格子也可以**——没填的档位自动回退到 tier 3（中间档），没填的簇回退到 `neutral`。可以从 4 个主象限各填 1 档开始跑起来，再慢慢补。\n\n完整写法见 [部署指南：语调网格设计](./GUIDE.md#第二步设计你的语调网格core_profiles)。\n\n### 手动覆盖（高级）\n\n如果你需要完全自定义查表逻辑（不同的情绪分类、不同的轴组合），可以手动注入函数：\n\n```js\nconst jiwen = createJiwen({\n  getPromptContext: (state) => { /* 自定义状态描述 */ },\n  getStyleGuidance: (state) => { /* 自定义风格指引 */ },\n});\n```\n\n### 轴配置\n\n所有数值都可以自定义。完整参数列表见上方参数表。\n\n```js\nconst jiwen = createJiwen({\n  axes: {\n    connection: [0, 1],\n    pride:      [-1, 1],\n    valence:    [-1, 1],\n    arousal:    [-1, 1],\n    immersion:  [0, 1],\n  },\n  rates: {\n    valenceSetpoint: -0.1,   // 角色自然偏冷\n    connectionAccel: 1.5,    // 30 分钟后加速\n    accelDelay: 30,\n    // ...其他参数按需开启\n  },\n  thresholds: {\n    observation:     0.20,\n    considerContact: 0.35,\n    forceContact:    0.50,\n    prideBlock:      0.50,\n  },\n});\n```\n\n## 参数模拟工具\n\n参数校准靠猜是猜不准的。`simulate.js` 提供事件线模拟器：给定一个场景和多组参数，输出完整的状态轨迹 CSV。\n\n```js\nconst { simulate, toCSV, toCompareTable } = require('@clarashafiq/jiwen/simulate');\n\nconst scenario = [\n  { time: 0,   action: 'set_last_message', content: '晚安，去睡了' },\n  { time: 60,  action: 'tick' },\n  { time: 120, action: 'tick' },\n  { time: 240, action: 'set_last_message', content: '早啊醒了' },\n  { time: 240, action: 'apply_delta', pride: -0.1, valence: +0.1 },\n  { time: 240, action: 'reset_connection' },\n];\n\nconst results = await simulate(scenario, [\n  { name: '参数A', connectionRateFn: () => 0.007, rates: { connectionAccel: 1.5, accelDelay: 30 } },\n  { name: '参数B', connectionRateFn: () => 0.007, rates: { connectionAccel: 2.5, accelDelay: 0 } },\n]);\n\nfor (const r of results) console.log(toCSV(r).csv);\nconsole.log(toCompareTable(results));\n```\n\n诊断列重点关注：\n\n- **`effective_pride`** — 骄傲是否真的在拦截开口。如果永远为 0，说明 pride 还没爬到阻断线时 connection 已经越过 forceContact 了，pride 参数形同虚设\n- **`in_force_contact`** — 角色是否频繁撞到强制开口线。太频繁 = 太焦虑，太少 = 太冷淡\n- **`in_valence_activity` / `in_arousal_agitation`** — 自我调节触发频率\n\n引擎自带 29 项测试（`node jiwen.test.js`），覆盖单调性、边界、阈值转移、诊断列、connection 重置回归。\n\n## 和记忆系统的关系\n\n积温只管「感觉」，不管「知道」。记忆系统告诉角色上次聊了什么、对方喜欢什么。积温告诉角色现在想不想开口、用什么语气。阈值触发时，记忆提供内容，积温提供动机。互补，不竞争。\n\n## 不只是主动开口\n\n这篇 README 介绍的是积温的核心用途：**让角色知道什么时候该说话。**\n\n但状态系统的价值不止于此。同样的五轴数值可以驱动角色**每一句日常回复的语气和态度**——不只是在阈值触发时生成主动消息，而是让骄傲、心情、焦躁程度实时染色到对话风格里。\n\n具体做法见 [部署指南：让 AI 角色拥有持续情绪](./GUIDE.md)。指南覆盖了语调网格设计（怎么把 valence x arousal x pride 映射成说话指令）、对话情绪分析 prompt 的写法、以及实际部署时会踩的坑。\n\n---\n\n参数是调出来的，不是算出来的。每个角色的速率和阈值都不一样，跑 `simulate.js` 看轨迹，跑起来再微调。\n\n名字来自农业的「积温」——植物靠累积热量判断什么时候开花，不是谁替它掷骰子。\n\n## 许可证\n\nMIT","readmeFilename":"README.md"}