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.
- package/ADVANCED_CONFIG_ZH.md +97 -0
- package/AGENT_INSTALL.md +173 -0
- package/AGENT_INSTALL_EN.md +173 -0
- package/INSTALL.md +256 -0
- package/SKILL.md +63 -0
- package/docs/COMMAND_REFERENCE.md +76 -0
- package/docs/COMMAND_REFERENCE_EN.md +79 -0
- package/esbuild.config.js +75 -0
- package/openclaw.plugin.json +6 -1
- package/package.json +13 -15
- package/scripts/build-web.mjs +46 -0
- package/scripts/install-dependencies.cjs +47 -0
- package/scripts/sync-plugin.mjs +802 -0
- package/scripts/verify-build.mjs +109 -0
- package/src/agents/nocturnal-dreamer.md +152 -0
- package/src/agents/nocturnal-philosopher.md +138 -0
- package/src/agents/nocturnal-reflector.md +126 -0
- package/src/agents/nocturnal-scribe.md +164 -0
- package/src/commands/capabilities.ts +85 -0
- package/{dist/commands/context.js → src/commands/context.ts} +78 -38
- package/src/commands/evolution-status.ts +146 -0
- package/src/commands/export.ts +111 -0
- package/src/commands/focus.ts +533 -0
- package/src/commands/nocturnal-review.ts +311 -0
- package/src/commands/nocturnal-rollout.ts +763 -0
- package/src/commands/nocturnal-train.ts +1002 -0
- package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
- package/src/commands/principle-rollback.ts +27 -0
- package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
- package/src/commands/samples.ts +60 -0
- package/src/commands/strategy.ts +38 -0
- package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
- package/src/commands/workflow-debug.ts +128 -0
- package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
- package/src/config/errors.ts +163 -0
- package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
- package/src/constants/diagnostician.ts +66 -0
- package/src/constants/tools.ts +62 -0
- package/src/core/adaptive-thresholds.ts +476 -0
- package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
- package/{dist/core/config.js → src/core/config.ts} +158 -46
- package/src/core/control-ui-db.ts +435 -0
- package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
- package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
- package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
- package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
- package/src/core/empathy-keyword-matcher.ts +327 -0
- package/src/core/empathy-types.ts +218 -0
- package/src/core/event-log.ts +544 -0
- package/src/core/evolution-engine.ts +612 -0
- package/src/core/evolution-logger.ts +353 -0
- package/src/core/evolution-migration.ts +77 -0
- package/src/core/evolution-reducer.ts +731 -0
- package/src/core/evolution-types.ts +456 -0
- package/src/core/external-training-contract.ts +527 -0
- package/src/core/focus-history.ts +1458 -0
- package/src/core/hygiene/tracker.ts +117 -0
- package/{dist/core/init.js → src/core/init.ts} +39 -26
- package/src/core/local-worker-routing.ts +617 -0
- package/{dist/core/migration.js → src/core/migration.ts} +18 -11
- package/src/core/model-deployment-registry.ts +722 -0
- package/src/core/model-training-registry.ts +813 -0
- package/src/core/nocturnal-arbiter.ts +706 -0
- package/src/core/nocturnal-candidate-scoring.ts +392 -0
- package/src/core/nocturnal-compliance.ts +1075 -0
- package/src/core/nocturnal-dataset.ts +668 -0
- package/src/core/nocturnal-executability.ts +428 -0
- package/src/core/nocturnal-export.ts +390 -0
- package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
- package/src/core/nocturnal-trajectory-extractor.ts +484 -0
- package/src/core/nocturnal-trinity.ts +1384 -0
- package/src/core/pain.ts +122 -0
- package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
- package/{dist/core/paths.js → src/core/paths.ts} +13 -4
- package/src/core/principle-training-state.ts +450 -0
- package/src/core/profile.ts +226 -0
- package/src/core/promotion-gate.ts +822 -0
- package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
- package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
- package/src/core/shadow-observation-registry.ts +534 -0
- package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
- package/src/core/thinking-models.ts +217 -0
- package/src/core/training-program.ts +630 -0
- package/src/core/trajectory-types.ts +243 -0
- package/src/core/trajectory.ts +1673 -0
- package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
- package/src/hooks/bash-risk.ts +171 -0
- package/src/hooks/edit-verification.ts +295 -0
- package/src/hooks/gate-block-helper.ts +160 -0
- package/src/hooks/gate.ts +210 -0
- package/src/hooks/gfi-gate.ts +177 -0
- package/src/hooks/lifecycle.ts +326 -0
- package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
- package/src/hooks/message-sanitize.ts +45 -0
- package/src/hooks/pain.ts +384 -0
- package/src/hooks/progressive-trust-gate.ts +174 -0
- package/src/hooks/prompt.ts +920 -0
- package/src/hooks/subagent.ts +207 -0
- package/src/hooks/thinking-checkpoint.ts +73 -0
- package/src/hooks/trajectory-collector.ts +290 -0
- package/src/http/principles-console-route.ts +716 -0
- package/src/i18n/commands.ts +117 -0
- package/src/index.ts +694 -0
- package/src/service/central-database.ts +831 -0
- package/src/service/control-ui-query-service.ts +888 -0
- package/src/service/evolution-query-service.ts +405 -0
- package/src/service/evolution-worker.ts +1646 -0
- package/src/service/health-query-service.ts +836 -0
- package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
- package/src/service/nocturnal-service.ts +1015 -0
- package/src/service/nocturnal-target-selector.ts +532 -0
- package/src/service/phase3-input-filter.ts +237 -0
- package/src/service/runtime-summary-service.ts +757 -0
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
- package/src/service/subagent-workflow/index.ts +51 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
- package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
- package/src/service/subagent-workflow/types.ts +378 -0
- package/src/service/subagent-workflow/workflow-store.ts +328 -0
- package/src/service/trajectory-service.ts +15 -0
- package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
- package/src/tools/deep-reflect.ts +349 -0
- package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
- package/src/types/event-types.ts +453 -0
- package/src/types/hygiene-types.ts +31 -0
- package/src/types/principle-tree-schema.ts +244 -0
- package/src/types/runtime-summary.ts +49 -0
- package/src/types.ts +74 -0
- package/src/utils/file-lock.ts +391 -0
- package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
- package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
- package/src/utils/io.ts +110 -0
- package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
- package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
- package/src/utils/subagent-probe.ts +94 -0
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
- package/templates/pain_settings.json +2 -1
- package/tests/README.md +120 -0
- package/tests/build-artifacts.test.ts +111 -0
- package/tests/commands/evolution-status.test.ts +222 -0
- package/tests/commands/evolver.test.ts +22 -0
- package/tests/commands/export.test.ts +78 -0
- package/tests/commands/nocturnal-review.test.ts +448 -0
- package/tests/commands/nocturnal-train.test.ts +97 -0
- package/tests/commands/pain.test.ts +108 -0
- package/tests/commands/samples.test.ts +65 -0
- package/tests/commands/strategy.test.ts +34 -0
- package/tests/commands/thinking-os.test.ts +88 -0
- package/tests/core/adaptive-thresholds.test.ts +261 -0
- package/tests/core/config-service.test.ts +89 -0
- package/tests/core/config.test.ts +90 -0
- package/tests/core/control-ui-db.test.ts +75 -0
- package/tests/core/core-template-guidance.test.ts +21 -0
- package/tests/core/detection-funnel.test.ts +63 -0
- package/tests/core/detection-service.test.ts +50 -0
- package/tests/core/dictionary-service.test.ts +116 -0
- package/tests/core/dictionary.test.ts +168 -0
- package/tests/core/empathy-keyword-matcher.test.ts +209 -0
- package/tests/core/event-log.test.ts +181 -0
- package/tests/core/evolution-e2e.test.ts +58 -0
- package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
- package/tests/core/evolution-engine.test.ts +562 -0
- package/tests/core/evolution-logger.test.ts +148 -0
- package/tests/core/evolution-migration.test.ts +50 -0
- package/tests/core/evolution-paths.test.ts +21 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
- package/tests/core/evolution-reducer.test.ts +180 -0
- package/tests/core/evolution-types-loop.test.ts +48 -0
- package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
- package/tests/core/external-training-contract.test.ts +463 -0
- package/tests/core/focus-history.test.ts +682 -0
- package/tests/core/init-flatten.test.ts +69 -0
- package/tests/core/init-refactor.test.ts +87 -0
- package/tests/core/init-v1.3.test.ts +46 -0
- package/tests/core/init.test.ts +190 -0
- package/tests/core/local-worker-routing.test.ts +757 -0
- package/tests/core/migration.test.ts +84 -0
- package/tests/core/model-deployment-registry.test.ts +845 -0
- package/tests/core/model-training-registry.test.ts +889 -0
- package/tests/core/nocturnal-arbiter.test.ts +494 -0
- package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
- package/tests/core/nocturnal-compliance.test.ts +646 -0
- package/tests/core/nocturnal-dataset.test.ts +892 -0
- package/tests/core/nocturnal-executability.test.ts +357 -0
- package/tests/core/nocturnal-export.test.ts +462 -0
- package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
- package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
- package/tests/core/nocturnal-trinity.test.ts +953 -0
- package/tests/core/pain.test.ts +33 -0
- package/tests/core/path-resolver.test.ts +57 -0
- package/tests/core/paths-refactor.test.ts +42 -0
- package/tests/core/phase7-rollout-integration.test.ts +477 -0
- package/tests/core/principle-training-state.test.ts +712 -0
- package/tests/core/profile.test.ts +56 -0
- package/tests/core/promotion-gate.test.ts +556 -0
- package/tests/core/risk-calculator.test.ts +168 -0
- package/tests/core/session-tracker.test.ts +191 -0
- package/tests/core/training-program.test.ts +472 -0
- package/tests/core/trajectory.test.ts +265 -0
- package/tests/core/workspace-context-factory.test.ts +18 -0
- package/tests/core/workspace-context.test.ts +134 -0
- package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
- package/tests/fixtures/production-compatibility.test.ts +147 -0
- package/tests/fixtures/production-mock-generator.ts +282 -0
- package/tests/hooks/bash-risk-integration.test.ts +137 -0
- package/tests/hooks/bash-risk.test.ts +81 -0
- package/tests/hooks/edit-verification.test.ts +678 -0
- package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
- package/tests/hooks/gate-edit-verification.test.ts +435 -0
- package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
- package/tests/hooks/gate.test.ts +271 -0
- package/tests/hooks/gfi-gate-unit.test.ts +422 -0
- package/tests/hooks/gfi-gate.test.ts +669 -0
- package/tests/hooks/lifecycle.test.ts +248 -0
- package/tests/hooks/llm.test.ts +308 -0
- package/tests/hooks/message-sanitize.test.ts +36 -0
- package/tests/hooks/pain.test.ts +141 -0
- package/tests/hooks/progressive-trust-gate.test.ts +277 -0
- package/tests/hooks/prompt.test.ts +1411 -0
- package/tests/hooks/subagent.test.ts +467 -0
- package/tests/hooks/thinking-gate.test.ts +313 -0
- package/tests/http/principles-console-route.test.ts +140 -0
- package/tests/hygiene-tracker.test.ts +77 -0
- package/tests/index.integration.test.ts +179 -0
- package/tests/index.shadow-routing.integration.test.ts +140 -0
- package/tests/index.test.ts +9 -0
- package/tests/integration/empathy-workflow-integration.test.ts +627 -0
- package/tests/service/control-ui-query-service.test.ts +121 -0
- package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
- package/tests/service/evolution-worker.test.ts +585 -0
- package/tests/service/nocturnal-runtime.test.ts +470 -0
- package/tests/service/nocturnal-service.test.ts +577 -0
- package/tests/service/nocturnal-target-selector.test.ts +615 -0
- package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
- package/tests/service/phase3-input-filter.test.ts +289 -0
- package/tests/service/runtime-summary-service.test.ts +919 -0
- package/tests/task-compliance.test.ts +166 -0
- package/tests/test-utils.ts +48 -0
- package/tests/tools/critique-prompt.test.ts +260 -0
- package/tests/tools/deep-reflect.test.ts +232 -0
- package/tests/tools/model-index.test.ts +246 -0
- package/tests/ui/app.test.tsx +114 -0
- package/tests/utils/file-lock.test.ts +407 -0
- package/tests/utils/hashing.test.ts +32 -0
- package/tests/utils/io.test.ts +39 -0
- package/tests/utils/nlp.test.ts +53 -0
- package/tests/utils/plugin-logger.test.ts +156 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/ui/src/App.tsx +45 -0
- package/ui/src/api.ts +216 -0
- package/ui/src/charts.tsx +586 -0
- package/ui/src/components/ErrorState.tsx +6 -0
- package/ui/src/components/Loading.tsx +13 -0
- package/ui/src/components/ProtectedRoute.tsx +12 -0
- package/ui/src/components/Shell.tsx +91 -0
- package/ui/src/components/WorkspaceConfig.tsx +146 -0
- package/ui/src/components/index.ts +5 -0
- package/ui/src/context/auth.tsx +80 -0
- package/ui/src/context/theme.tsx +66 -0
- package/ui/src/hooks/useAutoRefresh.ts +39 -0
- package/ui/src/i18n/ui.ts +363 -0
- package/ui/src/main.tsx +16 -0
- package/ui/src/pages/EvolutionPage.tsx +352 -0
- package/ui/src/pages/FeedbackPage.tsx +140 -0
- package/ui/src/pages/GateMonitorPage.tsx +136 -0
- package/ui/src/pages/LoginPage.tsx +88 -0
- package/ui/src/pages/OverviewPage.tsx +238 -0
- package/ui/src/pages/SamplesPage.tsx +174 -0
- package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
- package/ui/src/styles.css +1661 -0
- package/ui/src/types.ts +368 -0
- package/ui/src/utils/format.ts +15 -0
- package/vitest.config.ts +23 -0
- package/dist/commands/capabilities.d.ts +0 -3
- package/dist/commands/capabilities.js +0 -73
- package/dist/commands/context.d.ts +0 -5
- package/dist/commands/evolution-status.d.ts +0 -4
- package/dist/commands/evolution-status.js +0 -117
- package/dist/commands/evolver.d.ts +0 -9
- package/dist/commands/evolver.js +0 -26
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -98
- package/dist/commands/focus.d.ts +0 -14
- package/dist/commands/focus.js +0 -457
- package/dist/commands/nocturnal-review.d.ts +0 -24
- package/dist/commands/nocturnal-review.js +0 -265
- package/dist/commands/nocturnal-rollout.d.ts +0 -27
- package/dist/commands/nocturnal-rollout.js +0 -671
- package/dist/commands/nocturnal-train.d.ts +0 -25
- package/dist/commands/nocturnal-train.js +0 -919
- package/dist/commands/pain.d.ts +0 -5
- package/dist/commands/principle-rollback.d.ts +0 -4
- package/dist/commands/principle-rollback.js +0 -22
- package/dist/commands/rollback.d.ts +0 -19
- package/dist/commands/samples.d.ts +0 -2
- package/dist/commands/samples.js +0 -55
- package/dist/commands/strategy.d.ts +0 -3
- package/dist/commands/strategy.js +0 -29
- package/dist/commands/thinking-os.d.ts +0 -2
- package/dist/config/defaults/runtime.d.ts +0 -40
- package/dist/config/errors.d.ts +0 -84
- package/dist/config/errors.js +0 -94
- package/dist/config/index.js +0 -7
- package/dist/constants/diagnostician.d.ts +0 -12
- package/dist/constants/diagnostician.js +0 -56
- package/dist/constants/tools.d.ts +0 -17
- package/dist/constants/tools.js +0 -54
- package/dist/core/adaptive-thresholds.d.ts +0 -186
- package/dist/core/adaptive-thresholds.js +0 -300
- package/dist/core/config-service.d.ts +0 -15
- package/dist/core/config.d.ts +0 -127
- package/dist/core/control-ui-db.d.ts +0 -95
- package/dist/core/control-ui-db.js +0 -292
- package/dist/core/detection-funnel.d.ts +0 -33
- package/dist/core/detection-service.d.ts +0 -15
- package/dist/core/dictionary-service.d.ts +0 -15
- package/dist/core/dictionary.d.ts +0 -38
- package/dist/core/event-log.d.ts +0 -82
- package/dist/core/event-log.js +0 -463
- package/dist/core/evolution-engine.d.ts +0 -118
- package/dist/core/evolution-engine.js +0 -464
- package/dist/core/evolution-logger.d.ts +0 -137
- package/dist/core/evolution-logger.js +0 -256
- package/dist/core/evolution-migration.d.ts +0 -5
- package/dist/core/evolution-migration.js +0 -65
- package/dist/core/evolution-reducer.d.ts +0 -98
- package/dist/core/evolution-reducer.js +0 -465
- package/dist/core/evolution-types.d.ts +0 -287
- package/dist/core/evolution-types.js +0 -78
- package/dist/core/external-training-contract.d.ts +0 -276
- package/dist/core/external-training-contract.js +0 -269
- package/dist/core/focus-history.d.ts +0 -210
- package/dist/core/focus-history.js +0 -1185
- package/dist/core/hygiene/tracker.d.ts +0 -22
- package/dist/core/hygiene/tracker.js +0 -106
- package/dist/core/init.d.ts +0 -12
- package/dist/core/local-worker-routing.d.ts +0 -175
- package/dist/core/local-worker-routing.js +0 -525
- package/dist/core/migration.d.ts +0 -6
- package/dist/core/model-deployment-registry.d.ts +0 -218
- package/dist/core/model-deployment-registry.js +0 -503
- package/dist/core/model-training-registry.d.ts +0 -295
- package/dist/core/model-training-registry.js +0 -475
- package/dist/core/nocturnal-arbiter.d.ts +0 -159
- package/dist/core/nocturnal-arbiter.js +0 -534
- package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
- package/dist/core/nocturnal-candidate-scoring.js +0 -266
- package/dist/core/nocturnal-compliance.d.ts +0 -175
- package/dist/core/nocturnal-compliance.js +0 -824
- package/dist/core/nocturnal-dataset.d.ts +0 -224
- package/dist/core/nocturnal-dataset.js +0 -443
- package/dist/core/nocturnal-executability.d.ts +0 -85
- package/dist/core/nocturnal-executability.js +0 -331
- package/dist/core/nocturnal-export.d.ts +0 -124
- package/dist/core/nocturnal-export.js +0 -275
- package/dist/core/nocturnal-paths.d.ts +0 -124
- package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
- package/dist/core/nocturnal-trajectory-extractor.js +0 -307
- package/dist/core/nocturnal-trinity.d.ts +0 -311
- package/dist/core/nocturnal-trinity.js +0 -880
- package/dist/core/pain.d.ts +0 -4
- package/dist/core/pain.js +0 -70
- package/dist/core/path-resolver.d.ts +0 -46
- package/dist/core/paths.d.ts +0 -65
- package/dist/core/principle-training-state.d.ts +0 -121
- package/dist/core/principle-training-state.js +0 -321
- package/dist/core/profile.d.ts +0 -62
- package/dist/core/profile.js +0 -210
- package/dist/core/promotion-gate.d.ts +0 -238
- package/dist/core/promotion-gate.js +0 -529
- package/dist/core/risk-calculator.d.ts +0 -22
- package/dist/core/session-tracker.d.ts +0 -99
- package/dist/core/shadow-observation-registry.d.ts +0 -217
- package/dist/core/shadow-observation-registry.js +0 -308
- package/dist/core/system-logger.d.ts +0 -8
- package/dist/core/thinking-models.d.ts +0 -38
- package/dist/core/thinking-models.js +0 -170
- package/dist/core/training-program.d.ts +0 -233
- package/dist/core/training-program.js +0 -433
- package/dist/core/trajectory.d.ts +0 -411
- package/dist/core/trajectory.js +0 -1307
- package/dist/core/workspace-context.d.ts +0 -71
- package/dist/hooks/bash-risk.d.ts +0 -57
- package/dist/hooks/bash-risk.js +0 -137
- package/dist/hooks/edit-verification.d.ts +0 -62
- package/dist/hooks/edit-verification.js +0 -256
- package/dist/hooks/gate-block-helper.d.ts +0 -44
- package/dist/hooks/gate-block-helper.js +0 -119
- package/dist/hooks/gate.d.ts +0 -24
- package/dist/hooks/gate.js +0 -173
- package/dist/hooks/gfi-gate.d.ts +0 -40
- package/dist/hooks/gfi-gate.js +0 -113
- package/dist/hooks/lifecycle.d.ts +0 -5
- package/dist/hooks/lifecycle.js +0 -284
- package/dist/hooks/llm.d.ts +0 -12
- package/dist/hooks/message-sanitize.d.ts +0 -3
- package/dist/hooks/message-sanitize.js +0 -37
- package/dist/hooks/pain.d.ts +0 -5
- package/dist/hooks/pain.js +0 -301
- package/dist/hooks/progressive-trust-gate.d.ts +0 -51
- package/dist/hooks/progressive-trust-gate.js +0 -89
- package/dist/hooks/prompt.d.ts +0 -47
- package/dist/hooks/prompt.js +0 -884
- package/dist/hooks/subagent.d.ts +0 -10
- package/dist/hooks/subagent.js +0 -387
- package/dist/hooks/thinking-checkpoint.d.ts +0 -37
- package/dist/hooks/thinking-checkpoint.js +0 -51
- package/dist/hooks/trajectory-collector.d.ts +0 -32
- package/dist/hooks/trajectory-collector.js +0 -256
- package/dist/http/principles-console-route.d.ts +0 -9
- package/dist/http/principles-console-route.js +0 -567
- package/dist/i18n/commands.d.ts +0 -26
- package/dist/i18n/commands.js +0 -116
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -581
- package/dist/service/central-database.d.ts +0 -104
- package/dist/service/central-database.js +0 -649
- package/dist/service/control-ui-query-service.d.ts +0 -221
- package/dist/service/control-ui-query-service.js +0 -543
- package/dist/service/empathy-observer-manager.d.ts +0 -52
- package/dist/service/empathy-observer-manager.js +0 -229
- package/dist/service/evolution-query-service.d.ts +0 -155
- package/dist/service/evolution-query-service.js +0 -258
- package/dist/service/evolution-worker.d.ts +0 -101
- package/dist/service/evolution-worker.js +0 -974
- package/dist/service/nocturnal-runtime.d.ts +0 -183
- package/dist/service/nocturnal-service.d.ts +0 -163
- package/dist/service/nocturnal-service.js +0 -787
- package/dist/service/nocturnal-target-selector.d.ts +0 -145
- package/dist/service/nocturnal-target-selector.js +0 -315
- package/dist/service/phase3-input-filter.d.ts +0 -73
- package/dist/service/phase3-input-filter.js +0 -172
- package/dist/service/runtime-summary-service.d.ts +0 -122
- package/dist/service/runtime-summary-service.js +0 -485
- package/dist/service/trajectory-service.d.ts +0 -2
- package/dist/service/trajectory-service.js +0 -15
- package/dist/tools/critique-prompt.d.ts +0 -14
- package/dist/tools/deep-reflect.d.ts +0 -39
- package/dist/tools/deep-reflect.js +0 -350
- package/dist/tools/model-index.d.ts +0 -9
- package/dist/types/event-types.d.ts +0 -306
- package/dist/types/event-types.js +0 -106
- package/dist/types/hygiene-types.d.ts +0 -20
- package/dist/types/hygiene-types.js +0 -12
- package/dist/types/runtime-summary.d.ts +0 -47
- package/dist/types/runtime-summary.js +0 -1
- package/dist/types.d.ts +0 -50
- package/dist/types.js +0 -22
- package/dist/utils/file-lock.d.ts +0 -71
- package/dist/utils/file-lock.js +0 -309
- package/dist/utils/glob-match.d.ts +0 -28
- package/dist/utils/hashing.d.ts +0 -9
- package/dist/utils/io.d.ts +0 -6
- package/dist/utils/io.js +0 -106
- package/dist/utils/nlp.d.ts +0 -9
- package/dist/utils/plugin-logger.d.ts +0 -39
- package/dist/utils/subagent-probe.d.ts +0 -34
- 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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
33
|
+
|
|
34
|
+
function normalizeSeverity(input?: string): 'mild' | 'moderate' | 'severe' {
|
|
16
35
|
const normalized = (input || '').toLowerCase();
|
|
17
|
-
if (normalized === 'severe' || normalized === 'high')
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
+
if (codeBlocksBefore % 2 === 1) return true;
|
|
88
|
+
|
|
69
89
|
return false;
|
|
70
90
|
}
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|