principles-disciple 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +6 -1
  10. package/package.json +13 -15
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/src/service/subagent-workflow/types.ts +378 -0
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -127
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -99
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -12
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -567
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. package/dist/utils/subagent-probe.js +0 -81
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import { PluginHookLlmOutputEvent, PluginHookAgentContext } from '../openclaw-sdk.js';
3
4
  import { trackFriction, trackLlmOutput, recordThinkingCheckpoint, resetFriction } from '../core/session-tracker.js';
4
5
  import { writePainFlag } from '../core/pain.js';
5
6
  import { ControlUiDatabase } from '../core/control-ui-db.js';
@@ -7,38 +8,57 @@ import { DetectionService } from '../core/detection-service.js';
7
8
  import { detectThinkingModelMatches, deriveThinkingScenarios } from '../core/thinking-models.js';
8
9
  import { WorkspaceContext } from '../core/workspace-context.js';
9
10
  import { sanitizeAssistantText } from './message-sanitize.js';
10
- const empathyDedupState = new Map();
11
- const empathyRateState = new Map();
12
- function clamp(value, min, max) {
11
+
12
+ export interface EmpathySignal {
13
+ detected: boolean;
14
+ severity: 'mild' | 'moderate' | 'severe';
15
+ confidence: number;
16
+ reason?: string;
17
+ mode?: 'structured' | 'legacy_tag';
18
+ }
19
+
20
+ type EmpathyRateState = {
21
+ turnScore: number;
22
+ hourScore: number;
23
+ hourWindowStart: number;
24
+ lastRunId?: string;
25
+ };
26
+
27
+ const empathyDedupState = new Map<string, number>();
28
+ const empathyRateState = new Map<string, EmpathyRateState>();
29
+
30
+ function clamp(value: number, min: number, max: number): number {
13
31
  return Math.max(min, Math.min(max, value));
14
32
  }
15
- function normalizeSeverity(input) {
33
+
34
+ function normalizeSeverity(input?: string): 'mild' | 'moderate' | 'severe' {
16
35
  const normalized = (input || '').toLowerCase();
17
- if (normalized === 'severe' || normalized === 'high')
18
- return 'severe';
19
- if (normalized === 'moderate' || normalized === 'medium')
20
- return 'moderate';
36
+ if (normalized === 'severe' || normalized === 'high') return 'severe';
37
+ if (normalized === 'moderate' || normalized === 'medium') return 'moderate';
21
38
  return 'mild';
22
39
  }
23
- function parseConfidence(raw) {
40
+
41
+ function parseConfidence(raw?: string): number {
24
42
  const parsed = Number(raw);
25
- if (!Number.isFinite(parsed))
26
- return 1;
43
+ if (!Number.isFinite(parsed)) return 1;
27
44
  return clamp(parsed, 0, 1);
28
45
  }
29
- function parseTrustedLegacyTag(text) {
46
+
47
+ function parseTrustedLegacyTag(text: string): RegExpMatchArray | null {
30
48
  return text.match(/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i);
31
49
  }
50
+
32
51
  /**
33
52
  * 检测标签是否是被用户诱导/引用输出的(回显),而非 LLM 主动输出的情绪信号
34
53
  */
35
- function isEchoedTag(text, tagMatch) {
54
+ function isEchoedTag(text: string, tagMatch: RegExpMatchArray): boolean {
36
55
  const tagIndex = tagMatch.index ?? 0;
37
56
  const before = text.substring(Math.max(0, tagIndex - 100), tagIndex).toLowerCase();
57
+
38
58
  // 1. 检查是否在引号内(用户引用)
39
59
  const quotesBefore = (before.match(/["'\u300c\u300d\u201c\u201d`]/g) || []).length;
40
- if (quotesBefore % 2 === 1)
41
- return true;
60
+ if (quotesBefore % 2 === 1) return true;
61
+
42
62
  // 2. Strong patterns: 用户指令关键词(任意位置匹配)
43
63
  const strongPatterns = [
44
64
  /用户(说|让|要求|让我输出)/,
@@ -48,9 +68,9 @@ function isEchoedTag(text, tagMatch) {
48
68
  /你让我输出/,
49
69
  ];
50
70
  for (const pattern of strongPatterns) {
51
- if (pattern.test(before))
52
- return true;
71
+ if (pattern.test(before)) return true;
53
72
  }
73
+
54
74
  // 3. Weak patterns: 仅在标签 15 字符内触发
55
75
  const weakPatterns = [
56
76
  { pattern: /echo/, window: 15 },
@@ -59,19 +79,21 @@ function isEchoedTag(text, tagMatch) {
59
79
  ];
60
80
  for (const { pattern, window } of weakPatterns) {
61
81
  const nearTag = text.substring(Math.max(0, tagIndex - window), tagIndex).toLowerCase();
62
- if (pattern.test(nearTag))
63
- return true;
82
+ if (pattern.test(nearTag)) return true;
64
83
  }
84
+
65
85
  // 4. 检查是否在代码块内
66
86
  const codeBlocksBefore = (before.match(/```/g) || []).length;
67
- if (codeBlocksBefore % 2 === 1)
68
- return true;
87
+ if (codeBlocksBefore % 2 === 1) return true;
88
+
69
89
  return false;
70
90
  }
71
- export function extractEmpathySignal(text) {
91
+
92
+ export function extractEmpathySignal(text: string): EmpathySignal {
72
93
  if (!text || typeof text !== 'string') {
73
94
  return { detected: false, severity: 'mild', confidence: 1 };
74
95
  }
96
+
75
97
  const xmlMatch = text.match(/<empathy\s+([^>]*)\/?>(?:<\/empathy>)?/i);
76
98
  if (xmlMatch?.[1]) {
77
99
  const attrs = xmlMatch[1];
@@ -83,11 +105,14 @@ export function extractEmpathySignal(text) {
83
105
  return { detected: true, severity, confidence, reason, mode: 'structured' };
84
106
  }
85
107
  }
108
+
86
109
  const jsonMatch = text.match(/"empathy"\s*:\s*\{[\s\S]*?\}/i);
87
110
  if (jsonMatch) {
88
111
  const jsonText = `{${jsonMatch[0]}}`;
89
112
  try {
90
- const parsed = JSON.parse(jsonText);
113
+ const parsed = JSON.parse(jsonText) as {
114
+ empathy?: { damageDetected?: boolean; severity?: string; confidence?: number; reason?: string };
115
+ };
91
116
  if (parsed.empathy?.damageDetected === true) {
92
117
  return {
93
118
  detected: true,
@@ -97,11 +122,11 @@ export function extractEmpathySignal(text) {
97
122
  mode: 'structured'
98
123
  };
99
124
  }
100
- }
101
- catch {
125
+ } catch {
102
126
  // ignore malformed snippet
103
127
  }
104
128
  }
129
+
105
130
  const tagMatch = parseTrustedLegacyTag(text);
106
131
  if (tagMatch) {
107
132
  if (isEchoedTag(text, tagMatch)) {
@@ -114,22 +139,25 @@ export function extractEmpathySignal(text) {
114
139
  mode: 'legacy_tag'
115
140
  };
116
141
  }
142
+
117
143
  return { detected: false, severity: 'mild', confidence: 1 };
118
144
  }
119
- function mapSeverityToPenalty(severity, config) {
145
+
146
+ function mapSeverityToPenalty(severity: 'mild' | 'moderate' | 'severe', config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']): number {
120
147
  const mild = Number(config.get('empathy_engine.penalties.mild') ?? 10);
121
148
  const moderate = Number(config.get('empathy_engine.penalties.moderate') ?? 25);
122
149
  const severe = Number(config.get('empathy_engine.penalties.severe') ?? 40);
123
- if (severity === 'severe')
124
- return severe;
125
- if (severity === 'moderate')
126
- return moderate;
150
+
151
+ if (severity === 'severe') return severe;
152
+ if (severity === 'moderate') return moderate;
127
153
  return mild;
128
154
  }
129
- function dedupeKey(sessionId, runId, signal) {
155
+
156
+ function dedupeKey(sessionId: string, runId: string, signal: EmpathySignal): string {
130
157
  return `${sessionId}:${runId}:${signal.severity}:${(signal.reason || '').slice(0, 80)}`;
131
158
  }
132
- function shouldDedupe(sessionId, runId, signal, windowMs) {
159
+
160
+ function shouldDedupe(sessionId: string, runId: string, signal: EmpathySignal, windowMs: number): boolean {
133
161
  const key = dedupeKey(sessionId, runId, signal);
134
162
  const now = Date.now();
135
163
  const last = empathyDedupState.get(key);
@@ -139,57 +167,88 @@ function shouldDedupe(sessionId, runId, signal, windowMs) {
139
167
  empathyDedupState.set(key, now);
140
168
  return false;
141
169
  }
142
- function resolveCalibrationFactor(event, config) {
143
- const table = config.get('empathy_engine.model_calibration');
144
- if (!table || typeof table !== 'object')
145
- return 1;
170
+
171
+ function resolveCalibrationFactor(
172
+ event: PluginHookLlmOutputEvent,
173
+ config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
174
+ ): number {
175
+ const table = config.get('empathy_engine.model_calibration') as Record<string, number> | undefined;
176
+ if (!table || typeof table !== 'object') return 1;
177
+
146
178
  const modelKey = `${event.provider}/${event.model}`;
147
179
  const factor = Number(table[modelKey] ?? 1);
148
- if (!Number.isFinite(factor))
149
- return 1;
180
+ if (!Number.isFinite(factor)) return 1;
150
181
  return clamp(factor, 0.1, 3);
151
182
  }
152
- function applyRateLimit(sessionId, runId, score, config) {
183
+
184
+ function applyRateLimit(
185
+ sessionId: string,
186
+ runId: string,
187
+ score: number,
188
+ config: ReturnType<typeof WorkspaceContext.fromHookContext>['config']
189
+ ): number {
153
190
  const maxPerTurn = Number(config.get('empathy_engine.rate_limit.max_per_turn') ?? 40);
154
191
  const maxPerHour = Number(config.get('empathy_engine.rate_limit.max_per_hour') ?? 120);
155
192
  const now = Date.now();
193
+
156
194
  const prev = empathyRateState.get(sessionId) ?? {
157
195
  turnScore: 0,
158
196
  hourScore: 0,
159
197
  hourWindowStart: now,
160
198
  lastRunId: runId,
161
199
  };
200
+
162
201
  if (prev.lastRunId !== runId) {
163
202
  prev.turnScore = 0;
164
203
  prev.lastRunId = runId;
165
204
  }
205
+
166
206
  if (now - prev.hourWindowStart >= 60 * 60 * 1000) {
167
207
  prev.hourScore = 0;
168
208
  prev.hourWindowStart = now;
169
209
  }
210
+
170
211
  const byTurn = Math.max(0, maxPerTurn - prev.turnScore);
171
212
  const byHour = Math.max(0, maxPerHour - prev.hourScore);
172
213
  const allowed = Math.max(0, Math.min(score, byTurn, byHour));
214
+
173
215
  prev.turnScore += allowed;
174
216
  prev.hourScore += allowed;
175
217
  empathyRateState.set(sessionId, prev);
218
+
176
219
  return allowed;
177
220
  }
178
- export function handleLlmOutput(event, ctx) {
179
- if (!ctx.workspaceDir || !ctx.sessionId)
180
- return;
221
+
222
+
223
+ export function isEmpathyAuditPayload(text: string): boolean {
224
+ if (!text || typeof text !== 'string') return false;
225
+ const trimmed = text.trim();
226
+ if (/^\{[\s\S]*"damageDetected"[\s\S]*\}$/.test(trimmed)) return true;
227
+ if (/^<empathy\s+([^>]*)\/?>/i.test(trimmed)) return true;
228
+ if (/^\s*\[EMOTIONAL_DAMAGE_DETECTED(?::(mild|moderate|severe))?\]\s*$/i.test(trimmed)) return true;
229
+ return false;
230
+ }
231
+
232
+ export function handleLlmOutput(
233
+ event: PluginHookLlmOutputEvent,
234
+ ctx: PluginHookAgentContext & { workspaceDir?: string }
235
+ ): void {
236
+ if (!ctx.workspaceDir || !ctx.sessionId) return;
237
+
181
238
  const wctx = WorkspaceContext.fromHookContext(ctx);
182
239
  const config = wctx.config;
183
240
  const eventLog = wctx.eventLog;
241
+
184
242
  // Track this turn in the core session memory
185
- const state = trackLlmOutput(ctx.sessionId, event.usage, config, ctx.workspaceDir);
243
+ const state = trackLlmOutput(ctx.sessionId, event.usage, config, ctx.workspaceDir, ctx.sessionKey, ctx.trigger);
244
+
186
245
  // We need actual assistant text to analyze
187
- if (!event.assistantTexts || event.assistantTexts.length === 0)
188
- return;
246
+ if (!event.assistantTexts || event.assistantTexts.length === 0) return;
247
+
189
248
  const text = event.assistantTexts.join('\n');
190
249
  const signal = extractEmpathySignal(text);
191
250
  const createdAt = new Date().toISOString();
192
- let assistantTurnId = null;
251
+ let assistantTurnId: number | null = null;
193
252
  try {
194
253
  assistantTurnId = wctx.trajectory?.recordAssistantTurn?.({
195
254
  sessionId: ctx.sessionId,
@@ -202,21 +261,24 @@ export function handleLlmOutput(event, ctx) {
202
261
  empathySignalJson: signal,
203
262
  createdAt,
204
263
  });
205
- }
206
- catch (error) {
264
+ } catch (error) {
207
265
  ctx.logger?.warn?.(`[PD:LLM] Failed to persist assistant turn to trajectory: ${String(error)}`);
208
266
  }
267
+
209
268
  // ── Track B: Semantic Pain Detection (V1.3.0 Funnel) ──
269
+ const detectionText = isEmpathyAuditPayload(text) ? '' : text;
210
270
  const detectionService = DetectionService.get(wctx.stateDir);
211
- const detection = detectionService.detect(text);
271
+ const detection = detectionService.detect(detectionText);
272
+
212
273
  if (detection.detected) {
213
274
  eventLog.recordRuleMatch(ctx.sessionId, {
214
275
  ruleId: detection.ruleId || detection.source,
215
276
  layer: detection.source === 'l1_exact' ? 'L1' : (detection.source === 'l2_cache' ? 'L2' : 'L3'),
216
277
  severity: detection.severity || 0,
217
- textPreview: text.substring(0, 100)
278
+ textPreview: detectionText.substring(0, 100)
218
279
  });
219
280
  }
281
+
220
282
  let painScore = detection.detected ? (detection.severity || 0) : 0;
221
283
  let source = detection.detected
222
284
  ? (detection.ruleId ? `llm_${detection.ruleId.toLowerCase()}` : `llm_${detection.source}`)
@@ -224,78 +286,18 @@ export function handleLlmOutput(event, ctx) {
224
286
  let matchedReason = detection.detected
225
287
  ? `Agent triggered pain detection (Source: ${detection.source}${detection.ruleId ? `, Rule: ${detection.ruleId}` : ''})`
226
288
  : '';
227
- // empathy sub-pipeline (enabled by default)
228
- const empathyEnabled = config.get('empathy_engine.enabled');
229
- if (empathyEnabled !== false) {
230
- if (signal.detected) {
231
- const dedupeWindow = Number(config.get('empathy_engine.dedupe_window_ms') ?? 60000);
232
- const deduped = shouldDedupe(ctx.sessionId, event.runId, signal, dedupeWindow);
233
- if (!deduped) {
234
- const baseScore = mapSeverityToPenalty(signal.severity, config);
235
- const weightedScore = Math.round(baseScore * signal.confidence);
236
- const calibrationFactor = resolveCalibrationFactor(event, config);
237
- const calibratedScore = Math.round(weightedScore * calibrationFactor);
238
- const boundedScore = applyRateLimit(ctx.sessionId, event.runId, calibratedScore, config);
239
- if (boundedScore > 0) {
240
- trackFriction(ctx.sessionId, boundedScore, `user_empathy_${signal.severity}`, ctx.workspaceDir, { source: 'user_empathy' });
241
- try {
242
- wctx.trajectory?.recordPainEvent?.({
243
- sessionId: ctx.sessionId,
244
- source: 'user_empathy',
245
- score: boundedScore,
246
- reason: signal.reason || 'Assistant self-reported user emotional distress.',
247
- severity: signal.severity,
248
- origin: 'assistant_self_report',
249
- confidence: signal.confidence,
250
- });
251
- }
252
- catch (error) {
253
- ctx.logger?.warn?.(`[PD:LLM] Failed to persist empathy pain event to trajectory: ${String(error)}`);
254
- }
255
- // Generate unique event ID for rollback support
256
- const eventId = `emp_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
257
- eventLog.recordPainSignal(ctx.sessionId, {
258
- score: boundedScore,
259
- source: 'user_empathy',
260
- reason: signal.reason || 'Assistant self-reported user emotional distress.',
261
- isRisky: false,
262
- origin: 'assistant_self_report',
263
- severity: signal.severity,
264
- confidence: signal.confidence,
265
- detection_mode: signal.mode,
266
- deduped: false,
267
- trigger_text_excerpt: text.substring(0, 120),
268
- raw_score: weightedScore,
269
- calibrated_score: calibratedScore,
270
- eventId,
271
- });
272
- }
273
- }
274
- else {
275
- eventLog.recordPainSignal(ctx.sessionId, {
276
- score: 0,
277
- source: 'user_empathy',
278
- reason: signal.reason || 'Deduped empathy signal.',
279
- isRisky: false,
280
- origin: 'assistant_self_report',
281
- severity: signal.severity,
282
- confidence: signal.confidence,
283
- detection_mode: signal.mode,
284
- deduped: true,
285
- trigger_text_excerpt: text.substring(0, 120),
286
- raw_score: Math.round(mapSeverityToPenalty(signal.severity, config) * signal.confidence),
287
- calibrated_score: Math.round(mapSeverityToPenalty(signal.severity, config) * signal.confidence * resolveCalibrationFactor(event, config))
288
- });
289
- }
290
- }
291
- }
289
+
292
290
  // ═══ Natural Language Rollback Detection ═══
293
- // Detect [EMPATHY_ROLLBACK_REQUEST] tag and trigger rollback
294
291
  const rollbackMatch = text.match(/^\s*\[EMPATHY_ROLLBACK_REQUEST\]\s*$/m);
295
292
  if (rollbackMatch) {
296
293
  const eventId = eventLog.getLastEmpathyEventId(ctx.sessionId);
297
294
  if (eventId) {
298
- const rolledBackScore = eventLog.rollbackEmpathyEvent(eventId, ctx.sessionId, 'Natural language rollback request detected', 'natural_language');
295
+ const rolledBackScore = eventLog.rollbackEmpathyEvent(
296
+ eventId,
297
+ ctx.sessionId,
298
+ 'Natural language rollback request detected',
299
+ 'natural_language'
300
+ );
299
301
  if (rolledBackScore > 0) {
300
302
  // Reset GFI after successful rollback
301
303
  resetFriction(ctx.sessionId, ctx.workspaceDir, {
@@ -305,28 +307,37 @@ export function handleLlmOutput(event, ctx) {
305
307
  }
306
308
  }
307
309
  }
310
+
308
311
  // 3. Paralysis Check (from session state tracker)
309
312
  const stuckThreshold = config.get('thresholds.stuck_loops_trigger') || 3;
310
313
  const inputThreshold = config.get('thresholds.cognitive_paralysis_input') || 4000;
311
314
  const paralysisScore = config.get('scores.paralysis') || 40;
315
+
312
316
  if (state.stuckLoops >= stuckThreshold && state.totalInputTokens > inputThreshold && painScore < paralysisScore) {
313
317
  painScore = paralysisScore;
314
318
  source = 'llm_paralysis';
315
319
  matchedReason = `Agent is stuck in low-output loops (${state.stuckLoops} consecutive turns with tiny output but huge context), indicating cognitive paralysis.`;
316
320
  }
321
+
317
322
  // If a pain threshold is crossed, write the autonomous pain flag
318
323
  const painTriggerThreshold = config.get('thresholds.pain_trigger') || 30;
319
324
  if (painScore >= painTriggerThreshold) {
320
325
  // Inject the actual text snippet that triggered this for the diagnostician to read later
321
326
  const snippet = text.length > 200 ? text.substring(0, 100) + '...' + text.substring(text.length - 100) : text;
322
- writePainFlag(ctx.workspaceDir, {
323
- source,
324
- score: String(painScore),
325
- time: new Date().toISOString(),
326
- reason: matchedReason,
327
- is_risky: 'false',
328
- trigger_text_preview: snippet
329
- });
327
+
328
+ try {
329
+ writePainFlag(ctx.workspaceDir, {
330
+ source,
331
+ score: String(painScore),
332
+ time: new Date().toISOString(),
333
+ reason: matchedReason,
334
+ is_risky: 'false',
335
+ trigger_text_preview: snippet
336
+ });
337
+ } catch (e) {
338
+ ctx.logger?.warn?.(`[PD:LLM] Failed to write pain flag: ${String(e)}`);
339
+ }
340
+
330
341
  eventLog.recordPainSignal(ctx.sessionId, {
331
342
  score: painScore,
332
343
  source: source,
@@ -334,6 +345,7 @@ export function handleLlmOutput(event, ctx) {
334
345
  isRisky: false
335
346
  });
336
347
  }
348
+
337
349
  // ═══ Thinking OS: Mental Model Usage Tracking ═══
338
350
  trackThinkingModelUsage({
339
351
  text,
@@ -345,41 +357,56 @@ export function handleLlmOutput(event, ctx) {
345
357
  logger: ctx.logger,
346
358
  });
347
359
  }
348
- function trackThinkingModelUsage(args) {
360
+
361
+ function trackThinkingModelUsage(args: {
362
+ text: string;
363
+ wctx: WorkspaceContext;
364
+ sessionId?: string;
365
+ runId: string;
366
+ assistantTurnId: number | null;
367
+ createdAt: string;
368
+ logger?: PluginHookAgentContext['logger'];
369
+ }): void {
349
370
  const { text, wctx, sessionId, runId, assistantTurnId, createdAt, logger } = args;
350
371
  const logPath = wctx.resolve('THINKING_OS_USAGE');
351
372
  const logDir = path.dirname(logPath);
352
- if (!fs.existsSync(logDir))
353
- fs.mkdirSync(logDir, { recursive: true });
354
- let usageLog = {};
373
+ if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
374
+
375
+ let usageLog: Record<string, number> = {};
376
+
355
377
  if (fs.existsSync(logPath)) {
356
378
  try {
357
379
  usageLog = JSON.parse(fs.readFileSync(logPath, 'utf8'));
358
- }
359
- catch (e) {
360
- console.error(`[PD:LLM] Failed to parse thinking OS usage log: ${String(e)}`);
380
+ } catch (e) {
381
+ logger?.error?.(`[PD:LLM] Failed to parse thinking OS usage log: ${String(e)}`);
361
382
  }
362
383
  }
384
+
363
385
  const matches = detectThinkingModelMatches(text);
364
386
  for (const match of matches) {
365
387
  usageLog[match.modelId] = (usageLog[match.modelId] || 0) + 1;
366
388
  }
389
+
367
390
  usageLog['_total_turns'] = (usageLog['_total_turns'] || 0) + 1;
391
+
368
392
  try {
369
393
  fs.writeFileSync(logPath, JSON.stringify(usageLog, null, 2), 'utf8');
394
+ } catch (e) {
395
+ logger?.error?.(`[PD:LLM] Failed to write thinking OS usage log: ${String(e)}`);
370
396
  }
371
- catch (e) {
372
- console.error(`[PD:LLM] Failed to write thinking OS usage log: ${String(e)}`);
373
- }
397
+
374
398
  if (matches.length === 0) {
375
399
  return;
376
400
  }
401
+
377
402
  if (sessionId) {
378
403
  recordThinkingCheckpoint(sessionId, wctx.workspaceDir);
379
404
  }
405
+
380
406
  if (!sessionId || !assistantTurnId) {
381
407
  return;
382
408
  }
409
+
383
410
  const uiDb = new ControlUiDatabase({ workspaceDir: wctx.workspaceDir });
384
411
  try {
385
412
  const recentContext = uiDb.getRecentThinkingContext(sessionId, createdAt);
@@ -397,6 +424,7 @@ function trackThinkingModelUsage(args) {
397
424
  eventType: event.eventType,
398
425
  }));
399
426
  const triggerExcerpt = text.length > 280 ? `${text.slice(0, 277)}...` : text;
427
+
400
428
  for (const match of matches) {
401
429
  const scenarios = deriveThinkingScenarios(match.modelId, {
402
430
  recentToolCalls: toolContext,
@@ -410,6 +438,7 @@ function trackThinkingModelUsage(args) {
410
438
  })),
411
439
  recentPrincipleEvents: principleContext,
412
440
  });
441
+
413
442
  uiDb.recordThinkingModelEvent({
414
443
  sessionId,
415
444
  runId,
@@ -424,11 +453,9 @@ function trackThinkingModelUsage(args) {
424
453
  createdAt,
425
454
  });
426
455
  }
427
- }
428
- catch (error) {
456
+ } catch (error) {
429
457
  logger?.warn?.(`[PD:LLM] Failed to persist thinking model events: ${String(error)}`);
430
- }
431
- finally {
458
+ } finally {
432
459
  uiDb.dispose();
433
460
  }
434
461
  }
@@ -0,0 +1,45 @@
1
+ import type { PluginHookBeforeMessageWriteEvent, PluginHookBeforeMessageWriteResult } from '../openclaw-sdk.js';
2
+
3
+ const INTERNAL_TAG_PATTERNS = [
4
+ /\[EMOTIONAL_DAMAGE_DETECTED(?::(?:mild|moderate|severe))?\]/gi,
5
+ /\[EMPATHY_ROLLBACK_REQUEST\]/gi,
6
+ /<empathy\s+[^>]*\/?>(?:<\/empathy>)?/gi,
7
+ ];
8
+
9
+ export function sanitizeAssistantText(text: string): string {
10
+ let result = text;
11
+ for (const pattern of INTERNAL_TAG_PATTERNS) {
12
+ result = result.replace(pattern, '');
13
+ }
14
+ return result
15
+ .replace(/[ \t]+\n/g, '\n')
16
+ .replace(/\n{3,}/g, '\n\n')
17
+ .trim();
18
+ }
19
+
20
+ export function handleBeforeMessageWrite(
21
+ event: PluginHookBeforeMessageWriteEvent,
22
+ ): PluginHookBeforeMessageWriteResult | void {
23
+ const msg = event.message as { role?: string; content?: unknown } | undefined;
24
+ if (!msg || msg.role !== 'assistant') return;
25
+
26
+ if (typeof msg.content === 'string') {
27
+ const sanitized = sanitizeAssistantText(msg.content);
28
+ if (sanitized !== msg.content) {
29
+ return { message: { ...msg, content: sanitized } as any };
30
+ }
31
+ return;
32
+ }
33
+
34
+ if (Array.isArray(msg.content)) {
35
+ const next = msg.content.map((part: any) => {
36
+ if (part && typeof part === 'object' && part.type === 'text' && typeof part.text === 'string') {
37
+ return { ...part, text: sanitizeAssistantText(part.text) };
38
+ }
39
+ return part;
40
+ });
41
+ return { message: { ...msg, content: next } as any };
42
+ }
43
+
44
+ return;
45
+ }