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,17 +1,35 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
export type RuleType = 'regex' | 'exact_match';
|
|
5
|
+
|
|
6
|
+
export interface PainRule {
|
|
7
|
+
type: RuleType;
|
|
8
|
+
pattern?: string; // For regex
|
|
9
|
+
phrases?: string[]; // For exact_match
|
|
10
|
+
severity: number;
|
|
11
|
+
hits: number;
|
|
12
|
+
status: 'active' | 'dormant' | 'archived';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PainDictionaryData {
|
|
16
|
+
rules: Record<string, PainRule>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
3
20
|
export const PAIN_PROTOCOL_TOKENS = [
|
|
4
21
|
'[EVOLUTION_ACK]',
|
|
5
22
|
'HEARTBEAT_OK',
|
|
6
23
|
'HEARTBEAT_CHECK',
|
|
7
|
-
];
|
|
8
|
-
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export function shouldIgnorePainProtocolText(text: string): boolean {
|
|
9
27
|
const normalized = text.trim();
|
|
10
|
-
if (!normalized)
|
|
11
|
-
return false;
|
|
28
|
+
if (!normalized) return false;
|
|
12
29
|
return PAIN_PROTOCOL_TOKENS.some((token) => normalized === token || normalized.startsWith(`${token} `) || normalized.includes(token));
|
|
13
30
|
}
|
|
14
|
-
|
|
31
|
+
|
|
32
|
+
const DEFAULT_RULES: Record<string, PainRule> = {
|
|
15
33
|
'P_CONFUSION_ZH': {
|
|
16
34
|
type: 'regex',
|
|
17
35
|
pattern: '我(似乎|好像)(不确定|不太确定|不清楚|困惑)',
|
|
@@ -41,33 +59,33 @@ const DEFAULT_RULES = {
|
|
|
41
59
|
status: 'active'
|
|
42
60
|
}
|
|
43
61
|
};
|
|
62
|
+
|
|
44
63
|
export class PainDictionary {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
constructor(stateDir) {
|
|
50
|
-
this.stateDir = stateDir;
|
|
64
|
+
private data: PainDictionaryData = { rules: {} };
|
|
65
|
+
private filePath: string;
|
|
66
|
+
private compiledRegex: Map<string, RegExp> = new Map();
|
|
67
|
+
|
|
68
|
+
constructor(private stateDir: string) {
|
|
51
69
|
this.filePath = path.join(stateDir, 'pain_dictionary.json');
|
|
52
70
|
}
|
|
53
|
-
|
|
71
|
+
|
|
72
|
+
load(): void {
|
|
54
73
|
if (fs.existsSync(this.filePath)) {
|
|
55
74
|
try {
|
|
56
75
|
this.data = JSON.parse(fs.readFileSync(this.filePath, 'utf8'));
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
76
|
+
} catch (e) {
|
|
59
77
|
console.error('[PD] Failed to parse pain_dictionary.json, using defaults.');
|
|
60
78
|
this.data = { rules: { ...DEFAULT_RULES } };
|
|
61
79
|
}
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
80
|
+
} else {
|
|
64
81
|
this.data = { rules: { ...DEFAULT_RULES } };
|
|
65
82
|
console.log(`[PD:Dictionary] Dictionary not found at ${this.filePath}, creating with default rules`);
|
|
66
83
|
this.flush();
|
|
67
84
|
}
|
|
68
85
|
this.compile();
|
|
69
86
|
}
|
|
70
|
-
|
|
87
|
+
|
|
88
|
+
private compile(): void {
|
|
71
89
|
this.compiledRegex.clear();
|
|
72
90
|
for (const [id, rule] of Object.entries(this.data.rules)) {
|
|
73
91
|
if (rule.type === 'regex' && rule.pattern) {
|
|
@@ -75,16 +93,19 @@ export class PainDictionary {
|
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
|
-
|
|
96
|
+
|
|
97
|
+
getRule(id: string): PainRule | undefined {
|
|
79
98
|
return this.data.rules[id];
|
|
80
99
|
}
|
|
81
|
-
|
|
100
|
+
|
|
101
|
+
getAllRules(): Record<string, PainRule> {
|
|
82
102
|
return this.data.rules;
|
|
83
103
|
}
|
|
104
|
+
|
|
84
105
|
/**
|
|
85
106
|
* Adds a new rule or updates an existing one.
|
|
86
107
|
*/
|
|
87
|
-
addRule(id, rule) {
|
|
108
|
+
addRule(id: string, rule: Omit<PainRule, 'hits'>): void {
|
|
88
109
|
this.data.rules[id] = {
|
|
89
110
|
...rule,
|
|
90
111
|
hits: this.data.rules[id]?.hits || 0
|
|
@@ -94,28 +115,29 @@ export class PainDictionary {
|
|
|
94
115
|
this.compiledRegex.set(id, new RegExp(rule.pattern, 'i'));
|
|
95
116
|
}
|
|
96
117
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
|
|
119
|
+
match(text: string): { ruleId: string; severity: number } | undefined {
|
|
120
|
+
if (shouldIgnorePainProtocolText(text)) return undefined;
|
|
121
|
+
|
|
122
|
+
let bestMatch: { ruleId: string; severity: number } | undefined = undefined;
|
|
123
|
+
|
|
101
124
|
for (const [id, rule] of Object.entries(this.data.rules)) {
|
|
102
|
-
if (rule.status !== 'active')
|
|
103
|
-
|
|
125
|
+
if (rule.status !== 'active') continue;
|
|
126
|
+
|
|
104
127
|
let matched = false;
|
|
105
128
|
if (rule.type === 'regex') {
|
|
106
129
|
const re = this.compiledRegex.get(id);
|
|
107
130
|
if (re) {
|
|
108
131
|
re.lastIndex = 0;
|
|
109
|
-
if (re.test(text))
|
|
110
|
-
matched = true;
|
|
132
|
+
if (re.test(text)) matched = true;
|
|
111
133
|
}
|
|
112
|
-
}
|
|
113
|
-
else if (rule.type === 'exact_match' && rule.phrases) {
|
|
134
|
+
} else if (rule.type === 'exact_match' && rule.phrases) {
|
|
114
135
|
const lowerText = text.toLowerCase();
|
|
115
136
|
if (rule.phrases.some(p => lowerText.includes(p.toLowerCase()))) {
|
|
116
137
|
matched = true;
|
|
117
138
|
}
|
|
118
139
|
}
|
|
140
|
+
|
|
119
141
|
if (matched) {
|
|
120
142
|
rule.hits++;
|
|
121
143
|
if (!bestMatch || rule.severity > bestMatch.severity) {
|
|
@@ -125,18 +147,19 @@ export class PainDictionary {
|
|
|
125
147
|
}
|
|
126
148
|
return bestMatch;
|
|
127
149
|
}
|
|
128
|
-
|
|
150
|
+
|
|
151
|
+
flush(): void {
|
|
129
152
|
try {
|
|
130
153
|
if (!fs.existsSync(this.stateDir)) {
|
|
131
154
|
fs.mkdirSync(this.stateDir, { recursive: true });
|
|
132
155
|
}
|
|
133
156
|
fs.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2), 'utf8');
|
|
134
|
-
}
|
|
135
|
-
catch (e) {
|
|
157
|
+
} catch (e) {
|
|
136
158
|
console.error('[PD] Failed to flush pain_dictionary.json:', e);
|
|
137
159
|
}
|
|
138
160
|
}
|
|
139
|
-
|
|
161
|
+
|
|
162
|
+
getStats(): { totalRules: number; totalHits: number } {
|
|
140
163
|
let totalHits = 0;
|
|
141
164
|
for (const rule of Object.values(this.data.rules)) {
|
|
142
165
|
totalHits += rule.hits || 0;
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Empathy Keyword Matcher
|
|
3
|
+
*
|
|
4
|
+
* Fast keyword-based empathy detection that replaces the previous
|
|
5
|
+
* LLM subagent-per-turn approach.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* User message → keyword matching → weighted score → GFI penalty
|
|
9
|
+
*
|
|
10
|
+
* The keyword store is periodically optimized by a subagent that analyzes
|
|
11
|
+
* recent conversations and updates keyword weights, discovers new terms,
|
|
12
|
+
* and removes false positives.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import {
|
|
18
|
+
EmpathyKeywordStore,
|
|
19
|
+
EmpathyKeywordEntry,
|
|
20
|
+
EmpathyKeywordStats,
|
|
21
|
+
EmpathyMatchResult,
|
|
22
|
+
EmpathyKeywordConfig,
|
|
23
|
+
SeedKeywordEntry,
|
|
24
|
+
EMPATHY_SEED_KEYWORDS,
|
|
25
|
+
DEFAULT_EMPATHY_KEYWORD_CONFIG,
|
|
26
|
+
scoreToSeverity,
|
|
27
|
+
} from './empathy-types.js';
|
|
28
|
+
|
|
29
|
+
const KEYWORD_STORE_FILE = 'empathy_keywords.json';
|
|
30
|
+
|
|
31
|
+
// =========================================================================
|
|
32
|
+
// Store Management
|
|
33
|
+
// =========================================================================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a default keyword store from seed keywords.
|
|
37
|
+
* Supports both Chinese and English keywords.
|
|
38
|
+
*/
|
|
39
|
+
export function createDefaultKeywordStore(language: 'zh' | 'en' = 'zh'): EmpathyKeywordStore {
|
|
40
|
+
const now = new Date().toISOString();
|
|
41
|
+
const terms: Record<string, EmpathyKeywordEntry> = {};
|
|
42
|
+
|
|
43
|
+
// Include all seed keywords (both zh and en)
|
|
44
|
+
for (const seed of EMPATHY_SEED_KEYWORDS) {
|
|
45
|
+
// For Chinese language, include all keywords
|
|
46
|
+
// For English language, include only English keywords
|
|
47
|
+
const isChinese = /[\u4e00-\u9fa5]/.test(seed.term);
|
|
48
|
+
if (language === 'zh' || !isChinese) {
|
|
49
|
+
terms[seed.term] = {
|
|
50
|
+
weight: seed.weight,
|
|
51
|
+
source: 'seed',
|
|
52
|
+
hitCount: 0,
|
|
53
|
+
falsePositiveRate: seed.initialFalsePositiveRate ?? 0.15, // Differentiated FPR (Finding #6)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const stats: EmpathyKeywordStats = {
|
|
59
|
+
totalHits: 0,
|
|
60
|
+
totalFalsePositives: 0,
|
|
61
|
+
optimizationCount: 0,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
version: 1,
|
|
66
|
+
lastUpdated: now,
|
|
67
|
+
lastOptimizedAt: now,
|
|
68
|
+
terms,
|
|
69
|
+
stats,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Loads the keyword store from disk, or creates a default one if not found.
|
|
75
|
+
* Respects the configured language setting.
|
|
76
|
+
*/
|
|
77
|
+
export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): EmpathyKeywordStore {
|
|
78
|
+
const filePath = path.join(stateDir, KEYWORD_STORE_FILE);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
if (!fs.existsSync(filePath)) {
|
|
82
|
+
const store = createDefaultKeywordStore(language);
|
|
83
|
+
saveKeywordStore(stateDir, store);
|
|
84
|
+
return store;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
88
|
+
const parsed = JSON.parse(raw);
|
|
89
|
+
|
|
90
|
+
// Validate structure
|
|
91
|
+
if (!parsed.terms || !parsed.stats || !parsed.version) {
|
|
92
|
+
console.warn('[PD:Empathy] Invalid keyword store format, creating default');
|
|
93
|
+
const store = createDefaultKeywordStore(language);
|
|
94
|
+
saveKeywordStore(stateDir, store);
|
|
95
|
+
return store;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return parsed as EmpathyKeywordStore;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.warn(`[PD:Empathy] Failed to load keyword store: ${e}`);
|
|
101
|
+
const store = createDefaultKeywordStore(language);
|
|
102
|
+
saveKeywordStore(stateDir, store);
|
|
103
|
+
return store;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Saves the keyword store to disk.
|
|
109
|
+
*/
|
|
110
|
+
export function saveKeywordStore(stateDir: string, store: EmpathyKeywordStore): void {
|
|
111
|
+
const filePath = path.join(stateDir, KEYWORD_STORE_FILE);
|
|
112
|
+
const dir = path.dirname(filePath);
|
|
113
|
+
|
|
114
|
+
if (!fs.existsSync(dir)) {
|
|
115
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
store.lastUpdated = new Date().toISOString();
|
|
119
|
+
fs.writeFileSync(filePath, JSON.stringify(store, null, 2), 'utf8');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// =========================================================================
|
|
123
|
+
// Keyword Matching
|
|
124
|
+
// =========================================================================
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Matches text against the keyword store and returns a structured result.
|
|
128
|
+
*
|
|
129
|
+
* This is the core function that replaces the previous LLM-based empathy detection.
|
|
130
|
+
* It runs in < 1ms for typical keyword stores (50-200 terms).
|
|
131
|
+
*/
|
|
132
|
+
export function matchEmpathyKeywords(
|
|
133
|
+
text: string,
|
|
134
|
+
store: EmpathyKeywordStore,
|
|
135
|
+
config: EmpathyKeywordConfig = DEFAULT_EMPATHY_KEYWORD_CONFIG,
|
|
136
|
+
): EmpathyMatchResult {
|
|
137
|
+
if (!text || typeof text !== 'string' || text.trim().length === 0) {
|
|
138
|
+
return {
|
|
139
|
+
matched: false,
|
|
140
|
+
score: 0,
|
|
141
|
+
matchedTerms: [],
|
|
142
|
+
severity: 'mild',
|
|
143
|
+
confidence: 0,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const lowerText = text.toLowerCase();
|
|
148
|
+
let totalScore = 0;
|
|
149
|
+
const matchedTerms: string[] = [];
|
|
150
|
+
|
|
151
|
+
for (const [term, entry] of Object.entries(store.terms)) {
|
|
152
|
+
if (lowerText.includes(term.toLowerCase())) {
|
|
153
|
+
// Weight adjusted by false positive rate
|
|
154
|
+
const adjustedWeight = entry.weight * (1 - entry.falsePositiveRate);
|
|
155
|
+
totalScore += adjustedWeight;
|
|
156
|
+
matchedTerms.push(term);
|
|
157
|
+
|
|
158
|
+
// Update hit stats
|
|
159
|
+
entry.hitCount++;
|
|
160
|
+
entry.lastHitAt = new Date().toISOString();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Cap score at 1.0
|
|
165
|
+
const cappedScore = Math.min(1, totalScore);
|
|
166
|
+
|
|
167
|
+
// Only consider matched if score exceeds threshold
|
|
168
|
+
const isMatched = cappedScore >= config.matchThreshold && matchedTerms.length > 0;
|
|
169
|
+
|
|
170
|
+
// Limit matched terms for performance
|
|
171
|
+
const limitedTerms = matchedTerms.slice(0, config.maxTermsPerMessage);
|
|
172
|
+
|
|
173
|
+
// Calculate confidence based on:
|
|
174
|
+
// - Number of matched terms (more terms = higher confidence)
|
|
175
|
+
// - Score relative to threshold (higher score = higher confidence)
|
|
176
|
+
const termConfidence = Math.min(1, limitedTerms.length / 3);
|
|
177
|
+
const scoreConfidence = Math.min(1, cappedScore / 0.8);
|
|
178
|
+
const confidence = Math.max(termConfidence, scoreConfidence);
|
|
179
|
+
|
|
180
|
+
const result: EmpathyMatchResult = {
|
|
181
|
+
matched: isMatched,
|
|
182
|
+
score: cappedScore,
|
|
183
|
+
matchedTerms: limitedTerms,
|
|
184
|
+
severity: scoreToSeverity(cappedScore),
|
|
185
|
+
confidence,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Update store stats
|
|
189
|
+
if (isMatched) {
|
|
190
|
+
store.stats.totalHits += limitedTerms.length;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// =========================================================================
|
|
197
|
+
// Keyword Store Updates
|
|
198
|
+
// =========================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Applies keyword updates from subagent optimization.
|
|
202
|
+
*
|
|
203
|
+
* This is called when the empathy optimizer subagent completes its analysis
|
|
204
|
+
* and returns suggested updates to the keyword store.
|
|
205
|
+
*/
|
|
206
|
+
export function applyKeywordUpdates(
|
|
207
|
+
store: EmpathyKeywordStore,
|
|
208
|
+
updates: Record<string, {
|
|
209
|
+
action: 'add' | 'update' | 'remove';
|
|
210
|
+
weight?: number;
|
|
211
|
+
falsePositiveRate?: number;
|
|
212
|
+
examples?: string[];
|
|
213
|
+
reasoning?: string;
|
|
214
|
+
}>,
|
|
215
|
+
): { added: number; updated: number; removed: number } {
|
|
216
|
+
let added = 0;
|
|
217
|
+
let updated = 0;
|
|
218
|
+
let removed = 0;
|
|
219
|
+
const now = new Date().toISOString();
|
|
220
|
+
|
|
221
|
+
for (const [term, update] of Object.entries(updates)) {
|
|
222
|
+
switch (update.action) {
|
|
223
|
+
case 'add':
|
|
224
|
+
if (!store.terms[term]) {
|
|
225
|
+
store.terms[term] = {
|
|
226
|
+
weight: update.weight ?? 0.5,
|
|
227
|
+
source: 'llm_discovered',
|
|
228
|
+
hitCount: 0,
|
|
229
|
+
falsePositiveRate: update.falsePositiveRate ?? 0.2,
|
|
230
|
+
examples: update.examples,
|
|
231
|
+
discoveredAt: now,
|
|
232
|
+
};
|
|
233
|
+
added++;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
|
|
237
|
+
case 'update':
|
|
238
|
+
if (store.terms[term]) {
|
|
239
|
+
if (update.weight !== undefined) {
|
|
240
|
+
store.terms[term].weight = update.weight;
|
|
241
|
+
}
|
|
242
|
+
if (update.falsePositiveRate !== undefined) {
|
|
243
|
+
store.terms[term].falsePositiveRate = update.falsePositiveRate;
|
|
244
|
+
}
|
|
245
|
+
if (update.examples) {
|
|
246
|
+
store.terms[term].examples = update.examples;
|
|
247
|
+
}
|
|
248
|
+
updated++;
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
|
|
252
|
+
case 'remove':
|
|
253
|
+
if (store.terms[term]) {
|
|
254
|
+
delete store.terms[term];
|
|
255
|
+
removed++;
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
store.lastOptimizedAt = now;
|
|
262
|
+
store.stats.optimizationCount++;
|
|
263
|
+
|
|
264
|
+
return { added, updated, removed };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// =========================================================================
|
|
268
|
+
// Optimization Trigger
|
|
269
|
+
// =========================================================================
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Checks if it's time to trigger subagent optimization.
|
|
273
|
+
*
|
|
274
|
+
* Returns true if either:
|
|
275
|
+
* - The number of turns since last optimization exceeds the interval
|
|
276
|
+
* - The time since last optimization exceeds the interval
|
|
277
|
+
*/
|
|
278
|
+
export function shouldTriggerOptimization(
|
|
279
|
+
store: EmpathyKeywordStore,
|
|
280
|
+
turnsSinceLastOptimization: number,
|
|
281
|
+
config: EmpathyKeywordConfig = DEFAULT_EMPATHY_KEYWORD_CONFIG,
|
|
282
|
+
): boolean {
|
|
283
|
+
const turnsExceeded = turnsSinceLastOptimization >= config.optimizationIntervalTurns;
|
|
284
|
+
|
|
285
|
+
const lastOpt = new Date(store.lastOptimizedAt).getTime();
|
|
286
|
+
const now = Date.now();
|
|
287
|
+
const timeExceeded = (now - lastOpt) >= config.optimizationIntervalMs;
|
|
288
|
+
|
|
289
|
+
return turnsExceeded || timeExceeded;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// =========================================================================
|
|
293
|
+
// Store Inspection
|
|
294
|
+
// =========================================================================
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Returns a summary of the keyword store for debugging/monitoring.
|
|
298
|
+
*/
|
|
299
|
+
export function getKeywordStoreSummary(store: EmpathyKeywordStore): {
|
|
300
|
+
totalTerms: number;
|
|
301
|
+
seedTerms: number;
|
|
302
|
+
discoveredTerms: number;
|
|
303
|
+
topHitTerms: { term: string; hitCount: number; weight: number }[];
|
|
304
|
+
highFalsePositiveTerms: { term: string; falsePositiveRate: number }[];
|
|
305
|
+
} {
|
|
306
|
+
const terms = Object.entries(store.terms);
|
|
307
|
+
const seedTerms = terms.filter(([, e]) => e.source === 'seed');
|
|
308
|
+
const discoveredTerms = terms.filter(([, e]) => e.source === 'llm_discovered');
|
|
309
|
+
|
|
310
|
+
const topHitTerms = terms
|
|
311
|
+
.map(([term, entry]) => ({ term, hitCount: entry.hitCount, weight: entry.weight }))
|
|
312
|
+
.sort((a, b) => b.hitCount - a.hitCount)
|
|
313
|
+
.slice(0, 10);
|
|
314
|
+
|
|
315
|
+
const highFalsePositiveTerms = terms
|
|
316
|
+
.filter(([, e]) => e.falsePositiveRate > 0.3)
|
|
317
|
+
.map(([term, entry]) => ({ term, falsePositiveRate: entry.falsePositiveRate }))
|
|
318
|
+
.sort((a, b) => b.falsePositiveRate - a.falsePositiveRate);
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
totalTerms: terms.length,
|
|
322
|
+
seedTerms: seedTerms.length,
|
|
323
|
+
discoveredTerms: discoveredTerms.length,
|
|
324
|
+
topHitTerms,
|
|
325
|
+
highFalsePositiveTerms,
|
|
326
|
+
};
|
|
327
|
+
}
|