create-principles-disciple 1.100.0 → 1.102.0
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/console/dist/server/index.js +9 -0
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +37 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +114 -13
- package/console/dist/server/routes/onboarding.d.ts +34 -0
- package/console/dist/server/routes/onboarding.js +324 -0
- package/console/dist/ui/App.js +74 -15
- package/console/dist/ui/api.d.ts +17 -1
- package/console/dist/ui/api.js +6 -1
- package/console/dist/ui/components/onboarding/CircuitDiagram.d.ts +8 -0
- package/console/dist/ui/components/onboarding/CircuitDiagram.js +18 -0
- package/console/dist/ui/components/onboarding/DemoResultView.d.ts +22 -0
- package/console/dist/ui/components/onboarding/DemoResultView.js +15 -0
- package/console/dist/ui/i18n/en.json +127 -0
- package/console/dist/ui/i18n/zh-CN.json +127 -0
- package/console/dist/ui/pages/activation/ActivationValidators.js +1 -1
- package/console/dist/ui/pages/control-center/AgentCard.js +10 -3
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +1 -1
- package/console/dist/ui/pages/settings/SettingsPage.js +64 -5
- package/console/dist/ui/pages/signal-keywords/KeywordEditDialog.d.ts +12 -0
- package/console/dist/ui/pages/signal-keywords/KeywordEditDialog.js +41 -0
- package/console/dist/ui/pages/signal-keywords/KeywordListSection.d.ts +10 -0
- package/console/dist/ui/pages/signal-keywords/KeywordListSection.js +39 -0
- package/console/dist/ui/pages/signal-keywords/PendingTermsSection.d.ts +14 -0
- package/console/dist/ui/pages/signal-keywords/PendingTermsSection.js +35 -0
- package/console/dist/ui/pages/signal-keywords/SignalKeywordsPage.d.ts +1 -0
- package/console/dist/ui/pages/signal-keywords/SignalKeywordsPage.js +49 -0
- package/console/dist/ui/pages/welcome/WelcomePage.d.ts +5 -0
- package/console/dist/ui/pages/welcome/WelcomePage.js +185 -0
- package/console/dist/ui/utils/__tests__/onboarding-state.test.d.ts +1 -0
- package/console/dist/ui/utils/__tests__/onboarding-state.test.js +72 -0
- package/console/dist/ui/utils/agent-metadata.d.ts +13 -0
- package/console/dist/ui/utils/agent-metadata.js +26 -0
- package/console/dist/ui/utils/onboarding-state.d.ts +25 -0
- package/console/dist/ui/utils/onboarding-state.js +77 -0
- package/console/dist/ui/utils/signal-keywords-api.d.ts +68 -0
- package/console/dist/ui/utils/signal-keywords-api.js +121 -0
- package/console/dist/ui/utils/signal-keywords-types.d.ts +57 -0
- package/console/dist/ui/utils/signal-keywords-types.js +10 -0
- package/console/dist/ui/utils/signal-keywords-validators.d.ts +20 -0
- package/console/dist/ui/utils/signal-keywords-validators.js +114 -0
- package/console/dist/web/assets/app.css +401 -0
- package/console/dist/web/assets/app.js +6904 -1835
- package/core/dist/index.d.ts +2 -0
- package/core/dist/index.d.ts.map +1 -1
- package/core/dist/index.js +1 -0
- package/core/dist/index.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/admission-gate.test.js +63 -1
- package/core/dist/runtime-v2/__tests__/admission-gate.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +21 -5
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/chain-integrity-attack.test.js +17 -0
- package/core/dist/runtime-v2/__tests__/chain-integrity-attack.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/chain-integrity-real-path.test.js +12 -0
- package/core/dist/runtime-v2/__tests__/chain-integrity-real-path.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js +28 -0
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/internalization-chain-integrity-read-model.test.js +168 -1
- package/core/dist/runtime-v2/__tests__/internalization-chain-integrity-read-model.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/pain-to-principle-service.test.js +8 -0
- package/core/dist/runtime-v2/__tests__/pain-to-principle-service.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/activation-dispatcher.test.js +53 -0
- package/core/dist/runtime-v2/activation/__tests__/activation-dispatcher.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/helpers.d.ts +21 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.js +132 -0
- package/core/dist/runtime-v2/activation/__tests__/helpers.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js +2 -117
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/activation-dispatcher.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-dispatcher.js +18 -2
- package/core/dist/runtime-v2/activation/activation-dispatcher.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +1 -1
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js +253 -6
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts +12 -0
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js +96 -2
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- package/core/dist/runtime-v2/admission-gate.d.ts +27 -0
- package/core/dist/runtime-v2/admission-gate.d.ts.map +1 -1
- package/core/dist/runtime-v2/admission-gate.js +55 -0
- package/core/dist/runtime-v2/admission-gate.js.map +1 -1
- package/core/dist/runtime-v2/cli/diagnose.d.ts +4 -0
- package/core/dist/runtime-v2/cli/diagnose.d.ts.map +1 -1
- package/core/dist/runtime-v2/cli/diagnose.js +25 -0
- package/core/dist/runtime-v2/cli/diagnose.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.d.ts +2 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.js +15 -0
- package/core/dist/runtime-v2/config/__tests__/internal-agent-names.test.js.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +7 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +28 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-redaction-deep.test.js +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-redaction-deep.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js.map +1 -1
- package/core/dist/runtime-v2/config/index.d.ts +5 -3
- package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/index.js +8 -2
- package/core/dist/runtime-v2/config/index.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +2 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js +12 -0
- package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js +25 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js +6 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.js +9 -0
- package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +110 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.js +7 -0
- package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js +114 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-profile-constants.d.ts +27 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.js +145 -0
- package/core/dist/runtime-v2/config/pd-profile-constants.js.map +1 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.d.ts +28 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.js +482 -0
- package/core/dist/runtime-v2/config/pd-validate-profile.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +26 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js +12 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +8 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +8 -2
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +6 -4
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +5 -3
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js +25 -0
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js +139 -0
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js +20 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js +7 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js +21 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js +23 -0
- package/core/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts +7 -0
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.js +22 -1
- package/core/dist/runtime-v2/internalization/artificer-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +2 -0
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.js +13 -0
- package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js +4 -1
- package/core/dist/runtime-v2/internalization/diag-distiller-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js +7 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js +4 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +7 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/index.d.ts +1 -1
- package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/index.js +1 -1
- package/core/dist/runtime-v2/internalization/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-task-guards.d.ts +7 -0
- package/core/dist/runtime-v2/internalization/internalization-task-guards.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js +8 -0
- package/core/dist/runtime-v2/internalization/internalization-task-guards.js.map +1 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.js +57 -1
- package/core/dist/runtime-v2/internalization-chain-integrity-read-model.js.map +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js.map +1 -1
- package/core/dist/runtime-v2/runner/__tests__/diagnose.test.js +91 -1
- package/core/dist/runtime-v2/runner/__tests__/diagnose.test.js.map +1 -1
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.js +39 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/keyword-stage.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.js +34 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/llm-stage.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.js +222 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/signal-collector.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.d.ts +2 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.js +35 -0
- package/core/dist/runtime-v2/signal-collector/__tests__/types.test.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts +5 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/index.js +5 -0
- package/core/dist/runtime-v2/signal-collector/index.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts +20 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js +61 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.d.ts +16 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.js +34 -0
- package/core/dist/runtime-v2/signal-collector/llm-stage.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.d.ts +16 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.js +71 -0
- package/core/dist/runtime-v2/signal-collector/signal-collector.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts +61 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/types.js +45 -0
- package/core/dist/runtime-v2/signal-collector/types.js.map +1 -0
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js +19 -0
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js.map +1 -1
- package/core/dist/runtime-v2/store/schema-conformance.test.js +73 -0
- package/core/dist/runtime-v2/store/schema-conformance.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js +41 -7
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +22 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +40 -3
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +9 -0
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +2 -2
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +1 -1
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/workflow-funnel-loader.js +1 -1
- package/core/dist/workflow-funnel-loader.js.map +1 -1
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +6 -0
- package/dist/i18n.js.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +3 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +167 -1
- package/dist/installer.js.map +1 -1
- package/dist/mvp-config.d.ts +8 -0
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +12 -2
- package/dist/mvp-config.js.map +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/candidate.d.ts.map +1 -1
- package/pd-cli/dist/commands/candidate.js +89 -7
- package/pd-cli/dist/commands/candidate.js.map +1 -1
- package/pd-cli/dist/commands/pain-retry.d.ts +3 -0
- package/pd-cli/dist/commands/pain-retry.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-retry.js +39 -14
- package/pd-cli/dist/commands/pain-retry.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +4 -0
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +244 -10
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/index.js +7 -84
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/commands/context.js +17 -11
- package/plugin/dist/commands/samples.js +25 -0
- package/plugin/dist/core/event-log.d.ts +11 -1
- package/plugin/dist/core/event-log.js +13 -0
- package/plugin/dist/core/init.js +3 -4
- package/plugin/dist/core/rule-host.d.ts +68 -0
- package/plugin/dist/core/rule-host.js +167 -28
- package/plugin/dist/core/signal-collector-host.d.ts +105 -0
- package/plugin/dist/core/signal-collector-host.js +337 -0
- package/plugin/dist/hooks/prompt.d.ts +3 -2
- package/plugin/dist/hooks/prompt.js +47 -571
- package/plugin/dist/types/event-types.d.ts +1 -1
- package/plugin/dist/types.d.ts +5 -25
- package/plugin/dist/types.js +4 -9
- package/plugin/dist/utils/hashing.js +1 -1
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import
|
|
3
|
-
import { clearInjectedProbationIds, getSession, resetFriction, setInjectedProbationIds, trackFriction, decayGfi, getGfiDecayElapsed } from '../core/session-tracker.js';
|
|
2
|
+
import { clearInjectedProbationIds, getSession, resetFriction, setInjectedProbationIds, decayGfi, getGfiDecayElapsed } from '../core/session-tracker.js';
|
|
4
3
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
5
|
-
import { defaultContextConfig } from '../types.js';
|
|
6
4
|
// local-worker-routing module and its routing helpers removed entirely per PRI-448.
|
|
7
5
|
// Routing guidance is no longer injected into prompts.
|
|
8
6
|
import { extractSummary, getHistoryVersions, parseWorkingMemorySection, workingMemoryToInjection, autoCompressFocus, safeReadCurrentFocus } from '../core/focus-history.js';
|
|
9
7
|
import { PathResolver } from '../core/path-resolver.js';
|
|
10
8
|
import { selectPrinciplesForInjection, DEFAULT_PRINCIPLE_BUDGET } from '../core/principle-injection.js';
|
|
11
|
-
import { getCachedMaskedPrincipleSet,
|
|
9
|
+
import { getCachedMaskedPrincipleSet, RUNTIME_V2_PRINCIPLE_BUDGET, trimToBudget, renderPrinciplesToDirectives } from '@principles/core/runtime-v2';
|
|
12
10
|
import { truncateInjectionToBudget } from '@principles/core/prompt-builder';
|
|
13
11
|
import { PromptActivationReader } from '../core/runtime-v2-prompt-activation-reader.js';
|
|
14
|
-
import {
|
|
15
|
-
import { severityToPenalty, DEFAULT_EMPATHY_KEYWORD_CONFIG } from '../core/empathy-types.js';
|
|
16
|
-
import { evaluatePainDiagnosticGate } from '../core/pain-diagnostic-gate.js';
|
|
17
|
-
import { emitPainDetectedEvent, buildTrajectoryEvidence } from './pain.js';
|
|
18
|
-
import { evaluateTriggerController } from '@principles/core/runtime-v2';
|
|
19
|
-
import { isSharedCooldownActive, markSharedEpisodeAsDiagnosed } from './trigger-cooldown-tracker.js';
|
|
20
|
-
import { buildEmpathyObservation, resolveSourceKind } from './raw-observation-adapter.js';
|
|
21
|
-
import { evaluateEvidenceTriage } from './triage-adapter.js';
|
|
22
|
-
import { loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
|
|
12
|
+
import { loadPdConfigForPlugin, loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
|
|
23
13
|
import { safeReadIntentDoc, resetIntentDocCacheForTest } from '../core/intent-doc-reader.js';
|
|
24
14
|
import { resolveIntentLang } from '../core/intent-doc-reader-adapter.js';
|
|
25
15
|
import { buildIntentFrictionBlock } from '@principles/core/runtime-v2';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { buildAgentIdentity, buildEmpathySilenceConstraint, extractUserMessageFromPrompt, assembleHeartbeatChecklist, formatCorePrinciples, formatEvolutionPrinciples, assembleAppendSystemContext, extractPhrasesFromReason, } from './prompt-helpers.js';
|
|
16
|
+
import { escapeXml, extractMessageContent, isMinimalTrigger, } from '@principles/core/prompt-builder';
|
|
17
|
+
import { buildAgentIdentity, buildEmpathySilenceConstraint, extractUserMessageFromPrompt, assembleHeartbeatChecklist, formatCorePrinciples, formatEvolutionPrinciples, assembleAppendSystemContext, } from './prompt-helpers.js';
|
|
18
|
+
import { SignalCollectorHost, createSignalLlmClassifierFromConfig } from '../core/signal-collector-host.js';
|
|
30
19
|
// ---------------------------------------------------------------------------
|
|
31
20
|
// Static file cache — avoids re-reading rarely-changing files every message
|
|
32
21
|
// ---------------------------------------------------------------------------
|
|
@@ -85,19 +74,6 @@ function cachedReadFile(filePath, workspaceDir) {
|
|
|
85
74
|
return '';
|
|
86
75
|
}
|
|
87
76
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Per-workspace empathy state. Keyed by workspaceDir to avoid cross-workspace
|
|
90
|
-
* state pollution. Previously module-level variables.
|
|
91
|
-
*/
|
|
92
|
-
const _empathyState = new Map();
|
|
93
|
-
function getEmpathyState(workspaceDir) {
|
|
94
|
-
let state = _empathyState.get(workspaceDir);
|
|
95
|
-
if (!state) {
|
|
96
|
-
state = { turnCounter: 0, keywordCache: null };
|
|
97
|
-
_empathyState.set(workspaceDir, state);
|
|
98
|
-
}
|
|
99
|
-
return state;
|
|
100
|
-
}
|
|
101
77
|
/**
|
|
102
78
|
* Reset all module-level prompt state for a workspace.
|
|
103
79
|
* Intended for test isolation — call in beforeEach().
|
|
@@ -105,90 +81,44 @@ function getEmpathyState(workspaceDir) {
|
|
|
105
81
|
export function resetPromptStateForTest(workspaceDir) {
|
|
106
82
|
if (workspaceDir) {
|
|
107
83
|
_staticFileCache.delete(workspaceDir);
|
|
108
|
-
_empathyState.delete(workspaceDir);
|
|
109
84
|
resetIntentDocCacheForTest(workspaceDir);
|
|
110
85
|
}
|
|
111
86
|
else {
|
|
112
87
|
_staticFileCache.clear();
|
|
113
|
-
_empathyState.clear();
|
|
114
88
|
resetIntentDocCacheForTest();
|
|
115
89
|
}
|
|
90
|
+
// CodeRabbit #6: 清理 host 缓存,避免 rate-limit/classifier 状态跨测试泄漏
|
|
91
|
+
_signalCollectorHosts.clear();
|
|
116
92
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (projectFocus !== 'full' && projectFocus !== 'summary' && projectFocus !== 'off')
|
|
131
|
-
return null;
|
|
132
|
-
config.projectFocus = projectFocus;
|
|
133
|
-
}
|
|
134
|
-
if (evolutionContext !== undefined) {
|
|
135
|
-
if (typeof evolutionContext !== 'object' || evolutionContext === null || Array.isArray(evolutionContext))
|
|
136
|
-
return null;
|
|
137
|
-
config.evolutionContext = { ...defaultContextConfig.evolutionContext };
|
|
138
|
-
const enabled = getOwnValue(evolutionContext, 'enabled');
|
|
139
|
-
const maxMessages = getOwnValue(evolutionContext, 'maxMessages');
|
|
140
|
-
const maxCharsPerMessage = getOwnValue(evolutionContext, 'maxCharsPerMessage');
|
|
141
|
-
if (enabled !== undefined) {
|
|
142
|
-
if (typeof enabled !== 'boolean')
|
|
143
|
-
return null;
|
|
144
|
-
config.evolutionContext.enabled = enabled;
|
|
145
|
-
}
|
|
146
|
-
if (maxMessages !== undefined) {
|
|
147
|
-
if (typeof maxMessages !== 'number' || !Number.isFinite(maxMessages))
|
|
148
|
-
return null;
|
|
149
|
-
config.evolutionContext.maxMessages = maxMessages;
|
|
150
|
-
}
|
|
151
|
-
if (maxCharsPerMessage !== undefined) {
|
|
152
|
-
if (typeof maxCharsPerMessage !== 'number' || !Number.isFinite(maxCharsPerMessage))
|
|
153
|
-
return null;
|
|
154
|
-
config.evolutionContext.maxCharsPerMessage = maxCharsPerMessage;
|
|
155
|
-
}
|
|
93
|
+
/**
|
|
94
|
+
* SignalCollectorHost 实例缓存(per-workspace)。
|
|
95
|
+
* 避免每条用户消息 new 一个 host;host 内部有 rate limit 状态需跨消息保留。
|
|
96
|
+
*/
|
|
97
|
+
const _signalCollectorHosts = new Map();
|
|
98
|
+
function getSignalCollectorHost(wctx, logger) {
|
|
99
|
+
let host = _signalCollectorHosts.get(wctx.workspaceDir);
|
|
100
|
+
if (!host) {
|
|
101
|
+
// 从 .pd/config.yaml 的 signalCollector runtimeProfile 构造 LLM classifier(配置单轨化)。
|
|
102
|
+
// 未配置/降级时返回 null,host 走纯关键词模式(spec §3.3 决策3)。
|
|
103
|
+
const llmClassifier = createSignalLlmClassifierFromConfig(wctx, logger);
|
|
104
|
+
host = new SignalCollectorHost(wctx, { llmClassifier });
|
|
105
|
+
_signalCollectorHosts.set(wctx.workspaceDir, host);
|
|
156
106
|
}
|
|
157
|
-
return
|
|
107
|
+
return host;
|
|
158
108
|
}
|
|
159
109
|
/**
|
|
160
110
|
* OpenClaw API Prompt Hook
|
|
161
111
|
* Constructs the system prompt injected into LLM context for Principles Disciple
|
|
162
112
|
*/
|
|
163
113
|
/**
|
|
164
|
-
* Loads context injection config from .
|
|
165
|
-
*
|
|
114
|
+
* Loads context injection config from .pd/config.yaml via loadPdConfigForPlugin.
|
|
115
|
+
* The resolved config is computed by the core config layer (pd-config-effective.ts),
|
|
116
|
+
* which merges user partial input with DEFAULT_CONTEXT_INJECTION defaults.
|
|
166
117
|
* @internal Used by evolution engine for context settings
|
|
167
118
|
*/
|
|
168
119
|
export function loadContextInjectionConfig(workspaceDir) {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
const raw = cachedReadFile(profilePath, workspaceDir);
|
|
172
|
-
if (raw) {
|
|
173
|
-
const profile = JSON.parse(raw);
|
|
174
|
-
if (profile && typeof profile === 'object' && !Array.isArray(profile)) {
|
|
175
|
-
const contextInjection = getOwnValue(profile, 'contextInjection');
|
|
176
|
-
if (contextInjection !== undefined) {
|
|
177
|
-
const parsed = parseContextInjectionConfig(contextInjection);
|
|
178
|
-
if (!parsed) {
|
|
179
|
-
console.warn(`[PD:Prompt] Invalid contextInjection config in ${profilePath}; using defaults.`);
|
|
180
|
-
return { ...defaultContextConfig };
|
|
181
|
-
}
|
|
182
|
-
return parsed;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
catch (e) {
|
|
188
|
-
// Failed to load config — continue with defaults, but log for diagnostics
|
|
189
|
-
console.warn(`[PD:Prompt] Failed to load contextInjection config: ${String(e)}`);
|
|
190
|
-
}
|
|
191
|
-
return { ...defaultContextConfig };
|
|
120
|
+
const result = loadPdConfigForPlugin(workspaceDir);
|
|
121
|
+
return { ...result.effective.resolvedContextInjection };
|
|
192
122
|
}
|
|
193
123
|
export async function handleBeforePromptBuild(event, ctx) {
|
|
194
124
|
const { workspaceDir } = ctx;
|
|
@@ -204,53 +134,28 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
204
134
|
if (sessionId) {
|
|
205
135
|
wctx.trajectory?.recordSession?.({ sessionId });
|
|
206
136
|
}
|
|
137
|
+
// 提前计算 lineage + userTurnCount(不依赖 isAgentToAgent),供后续 detectSync 使用。
|
|
138
|
+
// detectSync 调用延后到 isAgentToAgent 解析之后(CodeRabbit #7: 避免 agent-to-agent 误判)。
|
|
139
|
+
let correctionUserText = null;
|
|
140
|
+
let correctionReferencesAssistantTurnId = null;
|
|
141
|
+
let correctionTurnIndex = 0;
|
|
207
142
|
if (sessionId && trigger === 'user' && Array.isArray(event.messages) && event.messages.length > 0) {
|
|
208
143
|
const latestUserIndex = [...event.messages]
|
|
209
144
|
.map((message, index) => ({ message, index }))
|
|
210
145
|
.reverse()
|
|
211
146
|
.find((entry) => entry.message?.role === 'user');
|
|
212
147
|
if (latestUserIndex) {
|
|
213
|
-
|
|
214
|
-
//
|
|
215
|
-
let correctionCue = null;
|
|
216
|
-
try {
|
|
217
|
-
const learner = CorrectionCueLearner.get(wctx.stateDir);
|
|
218
|
-
const matchResult = learner.match(userText);
|
|
219
|
-
if (matchResult.matched) {
|
|
220
|
-
correctionCue = matchResult.matchedTerms[0] ?? null;
|
|
221
|
-
learner.recordHits(matchResult.matchedTerms);
|
|
222
|
-
// TP for high-confidence; flush hitCount for low-confidence
|
|
223
|
-
if (correctionCue && matchResult.confidence >= 0.5) {
|
|
224
|
-
learner.recordTruePositive(correctionCue);
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
learner.flush();
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
catch (learnerErr) {
|
|
232
|
-
// Fallback to hardcoded detection if learner fails — log for observability
|
|
233
|
-
correctionCue = coreDetectCorrectionCue(userText);
|
|
234
|
-
logger?.warn?.(`[PD:Prompt] CorrectionCueLearner.match() failed (${String(learnerErr)}), fallback=${correctionCue ? `matched="${correctionCue}"` : 'no-match'}`);
|
|
235
|
-
}
|
|
236
|
-
let referencesAssistantTurnId = null;
|
|
148
|
+
correctionUserText = extractMessageContent(latestUserIndex.message);
|
|
149
|
+
// lineage: 关联到前置 assistant turn(诊断 evidence JOIN 用)。host 不感知 trajectory 结构,由这里算好传入。
|
|
237
150
|
const hasPriorAssistant = event.messages
|
|
238
151
|
.slice(0, latestUserIndex.index)
|
|
239
152
|
.some((message) => message?.role === 'assistant');
|
|
240
153
|
if (hasPriorAssistant) {
|
|
241
154
|
const turns = wctx.trajectory?.listAssistantTurns?.(sessionId) ?? [];
|
|
242
155
|
const lastAssistant = turns[turns.length - 1];
|
|
243
|
-
|
|
156
|
+
correctionReferencesAssistantTurnId = lastAssistant?.id ?? null;
|
|
244
157
|
}
|
|
245
|
-
|
|
246
|
-
wctx.trajectory?.recordUserTurn?.({
|
|
247
|
-
sessionId,
|
|
248
|
-
turnIndex: userTurnCount,
|
|
249
|
-
rawText: userText,
|
|
250
|
-
correctionDetected: Boolean(correctionCue),
|
|
251
|
-
correctionCue,
|
|
252
|
-
referencesAssistantTurnId,
|
|
253
|
-
});
|
|
158
|
+
correctionTurnIndex = event.messages.filter((message) => message?.role === 'user').length;
|
|
254
159
|
}
|
|
255
160
|
}
|
|
256
161
|
// Load context injection configuration
|
|
@@ -281,402 +186,21 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
281
186
|
// Also detects empathy observer output (prevent recursion) and agent-to-agent messages.
|
|
282
187
|
const { message: latestUserMessage, isAgentToAgent } = extractUserMessageFromPrompt(event.prompt || '', sessionId);
|
|
283
188
|
const isUserInteraction = trigger === 'user' || trigger === 'api' || !trigger;
|
|
284
|
-
// Empathy Observer: keyword fast-path + optional LLM deep analysis (zero latency async dispatch)
|
|
285
|
-
const empathyEnabled = wctx.config.get('empathy_engine.enabled') !== false;
|
|
286
|
-
logger?.info?.(`[PD:Empathy] Conditions: enabled=${empathyEnabled}, isUser=${isUserInteraction}, sessionId=${!!sessionId}, api=${!!api}, !agentToAgent=${!isAgentToAgent}, workspaceDir=${!!workspaceDir}, hasMessage=${!!latestUserMessage}`);
|
|
287
189
|
// Track if we should inject behavioral constraints (will be added to appendSystemContext later)
|
|
190
|
+
// 注:原 empathy 检测门控(empathyEnabled)已移除,检测职责由 SignalCollectorHost 接管。
|
|
191
|
+
// behavioral 约束注入是独立职责,保留门控。
|
|
288
192
|
let shouldInjectBehavioralConstraints = false;
|
|
289
|
-
if (
|
|
193
|
+
if (isUserInteraction && sessionId && api && !isAgentToAgent) {
|
|
290
194
|
shouldInjectBehavioralConstraints = true;
|
|
291
|
-
// ── Empathy Hybrid Matching (keyword + subagent sampling) ──
|
|
292
|
-
// Fast keyword scan on every turn, with strategic subagent sampling
|
|
293
|
-
// for boundary cases and random discovery of new expressions.
|
|
294
|
-
if (workspaceDir && latestUserMessage) {
|
|
295
|
-
try {
|
|
296
|
-
const msgPreview = latestUserMessage.substring(0, 200).replace(/\n/g, ' ');
|
|
297
|
-
logger?.info?.(`[PD:Empathy] Processing user message: "${msgPreview}" (trigger=${trigger}, promptLen=${latestUserMessage.length})`);
|
|
298
|
-
const lang = wctx.config.get('language') || 'zh';
|
|
299
|
-
// Load keyword store once, cache per-workspace (Finding #7: avoid per-turn I/O)
|
|
300
|
-
const empathyState = getEmpathyState(workspaceDir);
|
|
301
|
-
if (!empathyState.keywordCache || empathyState.keywordCache.lang !== lang) {
|
|
302
|
-
empathyState.keywordCache = { store: loadKeywordStore(wctx.stateDir, lang), lang };
|
|
303
|
-
}
|
|
304
|
-
const keywordStore = empathyState.keywordCache.store;
|
|
305
|
-
const matchResult = matchEmpathyKeywords(latestUserMessage, keywordStore);
|
|
306
|
-
// Increment turn counter (Finding #3: session.turnCount doesn't exist)
|
|
307
|
-
empathyState.turnCounter++;
|
|
308
|
-
const turnCount = empathyState.turnCounter;
|
|
309
|
-
const painTrigger = wctx.config.get('thresholds.pain_trigger') || 40;
|
|
310
|
-
const highGfiThreshold = Math.max(wctx.config.get('severity_thresholds.high') || 70, painTrigger + 30);
|
|
311
|
-
if (matchResult.matched) {
|
|
312
|
-
const penalty = severityToPenalty(matchResult.severity, DEFAULT_EMPATHY_KEYWORD_CONFIG);
|
|
313
|
-
// trackFriction signature: (sessionId, deltaF: number, hash: string, workspaceDir?, options?)
|
|
314
|
-
trackFriction(sessionId, penalty, 'empathy_keyword_match', workspaceDir, {
|
|
315
|
-
source: 'user_empathy',
|
|
316
|
-
});
|
|
317
|
-
logger?.info?.(`[PD:Empathy] MATCH: "${matchResult.matchedTerms.join(', ')}" → severity=${matchResult.severity}, score=${matchResult.score.toFixed(2)}, penalty=${penalty}`);
|
|
318
|
-
const currentSession = getSession(sessionId);
|
|
319
|
-
const currentGfi = currentSession?.currentGfi ?? 0;
|
|
320
|
-
if (currentGfi >= highGfiThreshold) {
|
|
321
|
-
const gfiPainScore = Math.min(Math.round(currentGfi), 60);
|
|
322
|
-
logger?.info?.(`[PD:Empathy] GFI-TRIGGERED: currentGfi=${currentGfi.toFixed(1)} >= highGfi=${highGfiThreshold}, emitting pain signal (score=${gfiPainScore})`);
|
|
323
|
-
// PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
|
|
324
|
-
// When either OFF → Gate A (PainDiagnosticGate, rollback).
|
|
325
|
-
const triageFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmission');
|
|
326
|
-
const defaultFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmissionDefault');
|
|
327
|
-
const useGateB = triageFlag.enabled && defaultFlag.enabled;
|
|
328
|
-
wctx.eventLog.recordPainSignal(sessionId, {
|
|
329
|
-
score: gfiPainScore,
|
|
330
|
-
source: 'user_empathy',
|
|
331
|
-
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
332
|
-
isRisky: false,
|
|
333
|
-
origin: 'system_infer',
|
|
334
|
-
severity: gfiPainScore >= 40 ? 'moderate' : 'mild',
|
|
335
|
-
confidence: 0.5,
|
|
336
|
-
detection_mode: 'structured',
|
|
337
|
-
deduped: false,
|
|
338
|
-
trigger_text_excerpt: sanitizeForEvidence(latestUserMessage, workspaceDir).substring(0, 120),
|
|
339
|
-
raw_score: gfiPainScore,
|
|
340
|
-
calibrated_score: gfiPainScore,
|
|
341
|
-
eventId: `empathy_gfi_${Date.now()}`,
|
|
342
|
-
});
|
|
343
|
-
// PRI-453: Generate painId early and write to trajectory.db via legacy
|
|
344
|
-
// recordPainEvent so that disabling SDK observability path does not lose
|
|
345
|
-
// trajectory coverage. canonicalPainId enables dedup.
|
|
346
|
-
const gfiPainId = `empathy_gfi_${Date.now()}`;
|
|
347
|
-
wctx.trajectory?.recordPainEvent?.({
|
|
348
|
-
sessionId,
|
|
349
|
-
source: 'user_empathy',
|
|
350
|
-
score: gfiPainScore,
|
|
351
|
-
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
352
|
-
origin: 'system_infer',
|
|
353
|
-
canonicalPainId: gfiPainId,
|
|
354
|
-
});
|
|
355
|
-
if (useGateB) {
|
|
356
|
-
// PRI-454: Gate B path — TriggerController owns admission
|
|
357
|
-
const rawObs = buildEmpathyObservation({
|
|
358
|
-
detectionSource: 'user_empathy',
|
|
359
|
-
isGfiTriggered: true,
|
|
360
|
-
sessionId,
|
|
361
|
-
});
|
|
362
|
-
const sourceKind = resolveSourceKind(rawObs);
|
|
363
|
-
const triage = evaluateEvidenceTriage(sourceKind, gfiPainScore);
|
|
364
|
-
if (triage.decision !== 'admit') {
|
|
365
|
-
logger?.info?.(`[PD:Empathy] Triage ${triage.decision}: ${triage.reason}`);
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
const cooldownActive = isSharedCooldownActive(sourceKind, sessionId, 'empathy_gfi_threshold');
|
|
369
|
-
const triggerDecision = evaluateTriggerController({
|
|
370
|
-
triageResult: triage,
|
|
371
|
-
isOwnerManual: false,
|
|
372
|
-
isCooldownActive: cooldownActive,
|
|
373
|
-
isValid: true,
|
|
374
|
-
score: gfiPainScore,
|
|
375
|
-
sessionId,
|
|
376
|
-
});
|
|
377
|
-
if (triggerDecision.shouldCreateDiagnosticTask) {
|
|
378
|
-
markSharedEpisodeAsDiagnosed(sourceKind, sessionId, 'empathy_gfi_threshold');
|
|
379
|
-
logger?.info?.(`[PD:Empathy] Gate B approved, calling emitPainDetectedEvent...`);
|
|
380
|
-
try {
|
|
381
|
-
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
382
|
-
await emitPainDetectedEvent(wctx, {
|
|
383
|
-
ts: new Date().toISOString(),
|
|
384
|
-
type: 'pain_detected',
|
|
385
|
-
data: {
|
|
386
|
-
painId: gfiPainId,
|
|
387
|
-
painType: 'user_frustration',
|
|
388
|
-
source: 'user_empathy',
|
|
389
|
-
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
390
|
-
score: gfiPainScore,
|
|
391
|
-
sessionId,
|
|
392
|
-
agentId: 'main',
|
|
393
|
-
provenance: 'openclaw_context_bound',
|
|
394
|
-
evidence,
|
|
395
|
-
},
|
|
396
|
-
}, { recordObservability: false });
|
|
397
|
-
logger?.info?.(`[PD:Empathy] emitPainDetectedEvent completed (GFI-triggered)`);
|
|
398
|
-
}
|
|
399
|
-
catch (emitErr) {
|
|
400
|
-
console.error(`[PD:Empathy] FAILED to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
401
|
-
logger?.warn?.(`[PD:Empathy] Failed to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
logger?.info?.(`[PD:Empathy] Gate B skipped: ${triggerDecision.reason}`);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
else {
|
|
410
|
-
// PRI-454: Gate A path (rollback when either flag is OFF)
|
|
411
|
-
const gate = evaluatePainDiagnosticGate({
|
|
412
|
-
source: 'user_empathy',
|
|
413
|
-
score: gfiPainScore,
|
|
414
|
-
currentGfi,
|
|
415
|
-
consecutiveErrors: currentSession?.consecutiveErrors ?? 0,
|
|
416
|
-
sessionId,
|
|
417
|
-
errorHash: 'empathy_gfi_threshold',
|
|
418
|
-
thresholds: {
|
|
419
|
-
painTrigger,
|
|
420
|
-
highSeverity: wctx.config.get('severity_thresholds.high') || 70,
|
|
421
|
-
semanticPain: Math.max(painTrigger, 60),
|
|
422
|
-
},
|
|
423
|
-
});
|
|
424
|
-
if (gate.shouldDiagnose) {
|
|
425
|
-
logger?.info?.(`[PD:Empathy] Gate approved, calling emitPainDetectedEvent...`);
|
|
426
|
-
try {
|
|
427
|
-
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
428
|
-
await emitPainDetectedEvent(wctx, {
|
|
429
|
-
ts: new Date().toISOString(),
|
|
430
|
-
type: 'pain_detected',
|
|
431
|
-
data: {
|
|
432
|
-
painId: gfiPainId,
|
|
433
|
-
painType: 'user_frustration',
|
|
434
|
-
source: 'user_empathy',
|
|
435
|
-
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
436
|
-
score: gfiPainScore,
|
|
437
|
-
sessionId,
|
|
438
|
-
agentId: 'main',
|
|
439
|
-
provenance: 'openclaw_context_bound',
|
|
440
|
-
evidence,
|
|
441
|
-
},
|
|
442
|
-
}, { recordObservability: false });
|
|
443
|
-
logger?.info?.(`[PD:Empathy] emitPainDetectedEvent completed (GFI-triggered)`);
|
|
444
|
-
}
|
|
445
|
-
catch (emitErr) {
|
|
446
|
-
console.error(`[PD:Empathy] FAILED to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
447
|
-
logger?.warn?.(`[PD:Empathy] Failed to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
logger?.info?.(`[PD:Empathy] GFI-triggered gate rejected: ${gate.detail}`);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
// ── Pipeline: Observer only runs when keyword matcher misses ──
|
|
458
|
-
const observer = resolveEmpathyObserver(wctx, logger);
|
|
459
|
-
if (observer) {
|
|
460
|
-
const scheduler = new AgentScheduler();
|
|
461
|
-
scheduler.register({
|
|
462
|
-
agentId: 'empathy-observer',
|
|
463
|
-
mode: 'realtime',
|
|
464
|
-
runner: observer,
|
|
465
|
-
});
|
|
466
|
-
logger?.info?.(`[PD:Empathy] Pipeline: Triggering background Empathy Observer for unmatched message: "${msgPreview}"`);
|
|
467
|
-
void scheduler.dispatch('empathy-observer', { userMessage: latestUserMessage })
|
|
468
|
-
.then(async (result) => {
|
|
469
|
-
if (result.damageDetected) {
|
|
470
|
-
logger?.info?.(`[PD:Empathy] Pipeline: Background Empathy Observer detected damage. Severity: ${result.severity}, Reason: ${result.reason}`);
|
|
471
|
-
// ── Persistence Contract ──
|
|
472
|
-
const painScore = scoreFromSeverityForSpec(result.severity, wctx);
|
|
473
|
-
trackFriction(sessionId, painScore, `observer_empathy_${result.severity}`, workspaceDir, { source: 'user_empathy' });
|
|
474
|
-
// ── Pipeline: feed back newly detected expressions into keyword store ──
|
|
475
|
-
if (result.reason) {
|
|
476
|
-
const rawLang = wctx.config.get('language');
|
|
477
|
-
const lang = rawLang === 'en' ? 'en' : 'zh';
|
|
478
|
-
const phrases = extractPhrasesFromReason(result.reason, lang);
|
|
479
|
-
if (phrases.length > 0) {
|
|
480
|
-
const updates = {};
|
|
481
|
-
for (const phrase of phrases) {
|
|
482
|
-
if (!Object.hasOwn(keywordStore.terms, phrase)) {
|
|
483
|
-
updates[phrase] = {
|
|
484
|
-
action: 'add',
|
|
485
|
-
weight: 0.4,
|
|
486
|
-
falsePositiveRate: 0.3,
|
|
487
|
-
reasoning: `Discovered by empathy observer: ${result.reason.substring(0, 100)}`,
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
if (Object.keys(updates).length > 0) {
|
|
492
|
-
const { added } = applyKeywordUpdates(keywordStore, updates);
|
|
493
|
-
if (added > 0) {
|
|
494
|
-
saveKeywordStore(wctx.stateDir, keywordStore);
|
|
495
|
-
logger?.info?.(`[PD:Empathy] Pipeline: added ${added} new terms from observer feedback`);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
const eventId = `emp_obs_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
501
|
-
wctx.eventLog.recordPainSignal(sessionId, {
|
|
502
|
-
score: painScore,
|
|
503
|
-
source: 'user_empathy',
|
|
504
|
-
reason: result.reason || 'Empathy observer detected likely user frustration.',
|
|
505
|
-
isRisky: false,
|
|
506
|
-
origin: 'system_infer',
|
|
507
|
-
severity: result.severity,
|
|
508
|
-
confidence: result.confidence,
|
|
509
|
-
detection_mode: 'structured',
|
|
510
|
-
deduped: false,
|
|
511
|
-
trigger_text_excerpt: sanitizeForEvidence(latestUserMessage, workspaceDir).substring(0, 120),
|
|
512
|
-
raw_score: painScore,
|
|
513
|
-
calibrated_score: painScore,
|
|
514
|
-
eventId,
|
|
515
|
-
});
|
|
516
|
-
// PRI-453: Generate painId early to pass as canonicalPainId for dedup.
|
|
517
|
-
// Declared outside try block so it's accessible to emitPainDetectedEvent
|
|
518
|
-
// later (lineage consistency: same id for trajectory + emitted event).
|
|
519
|
-
const observerPainId = `empathy_gfi_${Date.now()}`;
|
|
520
|
-
try {
|
|
521
|
-
wctx.trajectory?.recordPainEvent?.({
|
|
522
|
-
sessionId,
|
|
523
|
-
source: 'user_empathy',
|
|
524
|
-
score: painScore,
|
|
525
|
-
reason: result.reason || 'Empathy observer detected likely user frustration.',
|
|
526
|
-
severity: result.severity,
|
|
527
|
-
origin: 'system_infer',
|
|
528
|
-
confidence: result.confidence,
|
|
529
|
-
text: sanitizeForEvidence(latestUserMessage, workspaceDir),
|
|
530
|
-
canonicalPainId: observerPainId,
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
catch (error) {
|
|
534
|
-
logger?.warn?.(`[PD:Empathy] Failed to persist trajectory: ${String(error)}`);
|
|
535
|
-
}
|
|
536
|
-
// Check if GFI triggers a pain event post-LLM validation
|
|
537
|
-
const freshSession = getSession(sessionId);
|
|
538
|
-
const freshGfi = freshSession?.currentGfi ?? 0;
|
|
539
|
-
if (freshGfi >= highGfiThreshold) {
|
|
540
|
-
const freshGfiPainScore = Math.min(Math.round(freshGfi), 60);
|
|
541
|
-
// PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
|
|
542
|
-
// When either OFF → Gate A (PainDiagnosticGate, rollback).
|
|
543
|
-
const triageFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmission');
|
|
544
|
-
const defaultFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmissionDefault');
|
|
545
|
-
const useGateB = triageFlag.enabled && defaultFlag.enabled;
|
|
546
|
-
if (useGateB) {
|
|
547
|
-
// PRI-454: Gate B path — TriggerController owns admission
|
|
548
|
-
const rawObs = buildEmpathyObservation({
|
|
549
|
-
detectionSource: 'user_empathy',
|
|
550
|
-
isGfiTriggered: true,
|
|
551
|
-
sessionId,
|
|
552
|
-
});
|
|
553
|
-
const sourceKind = resolveSourceKind(rawObs);
|
|
554
|
-
const triage = evaluateEvidenceTriage(sourceKind, freshGfiPainScore);
|
|
555
|
-
if (triage.decision !== 'admit') {
|
|
556
|
-
logger?.info?.(`[PD:Empathy] Pipeline observer triage ${triage.decision}: ${triage.reason}`);
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
const cooldownActive = isSharedCooldownActive(sourceKind, sessionId, 'empathy_gfi_observer');
|
|
560
|
-
const triggerDecision = evaluateTriggerController({
|
|
561
|
-
triageResult: triage,
|
|
562
|
-
isOwnerManual: false,
|
|
563
|
-
isCooldownActive: cooldownActive,
|
|
564
|
-
isValid: true,
|
|
565
|
-
score: freshGfiPainScore,
|
|
566
|
-
sessionId,
|
|
567
|
-
});
|
|
568
|
-
if (triggerDecision.shouldCreateDiagnosticTask) {
|
|
569
|
-
markSharedEpisodeAsDiagnosed(sourceKind, sessionId, 'empathy_gfi_observer');
|
|
570
|
-
logger?.info?.(`[PD:Empathy] Pipeline Gate B approved (observer), calling emitPainDetectedEvent...`);
|
|
571
|
-
try {
|
|
572
|
-
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
573
|
-
// PRI-453: Reuse observerPainId for lineage consistency —
|
|
574
|
-
// the same id is used as canonicalPainId in recordPainEvent
|
|
575
|
-
// and as painId in the emitted event, so EvidenceChainConsoleModel
|
|
576
|
-
// can JOIN pain_events.canonical_pain_id = tasks.input_ref.
|
|
577
|
-
await emitPainDetectedEvent(wctx, {
|
|
578
|
-
ts: new Date().toISOString(),
|
|
579
|
-
type: 'pain_detected',
|
|
580
|
-
data: {
|
|
581
|
-
painId: observerPainId,
|
|
582
|
-
painType: 'user_frustration',
|
|
583
|
-
source: 'user_empathy',
|
|
584
|
-
reason: `Accumulated GFI (${freshGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Verified by Empathy Observer.`,
|
|
585
|
-
score: freshGfiPainScore,
|
|
586
|
-
sessionId,
|
|
587
|
-
agentId: 'main',
|
|
588
|
-
provenance: 'openclaw_context_bound',
|
|
589
|
-
evidence,
|
|
590
|
-
},
|
|
591
|
-
}, { recordObservability: false });
|
|
592
|
-
}
|
|
593
|
-
catch (emitErr) {
|
|
594
|
-
logger?.error?.(`[PD:Empathy] Pipeline FAILED to emit observer-triggered pain event: ${String(emitErr)}`);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
logger?.info?.(`[PD:Empathy] Pipeline Gate B skipped (observer): ${triggerDecision.reason}`);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
// PRI-454: Gate A path (rollback when either flag is OFF)
|
|
604
|
-
const gate = evaluatePainDiagnosticGate({
|
|
605
|
-
source: 'user_empathy',
|
|
606
|
-
score: freshGfiPainScore,
|
|
607
|
-
currentGfi: freshGfi,
|
|
608
|
-
consecutiveErrors: freshSession?.consecutiveErrors ?? 0,
|
|
609
|
-
sessionId,
|
|
610
|
-
errorHash: 'empathy_gfi_threshold',
|
|
611
|
-
thresholds: {
|
|
612
|
-
painTrigger,
|
|
613
|
-
highSeverity: wctx.config.get('severity_thresholds.high') || 70,
|
|
614
|
-
semanticPain: Math.max(painTrigger, 60),
|
|
615
|
-
},
|
|
616
|
-
});
|
|
617
|
-
if (gate.shouldDiagnose) {
|
|
618
|
-
logger?.info?.(`[PD:Empathy] Pipeline GFI threshold crossed after background observer. Emitting pain signal...`);
|
|
619
|
-
try {
|
|
620
|
-
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
621
|
-
// PRI-453: Reuse observerPainId for lineage consistency —
|
|
622
|
-
// the same id is used as canonicalPainId in recordPainEvent
|
|
623
|
-
// and as painId in the emitted event, so EvidenceChainConsoleModel
|
|
624
|
-
// can JOIN pain_events.canonical_pain_id = tasks.input_ref.
|
|
625
|
-
await emitPainDetectedEvent(wctx, {
|
|
626
|
-
ts: new Date().toISOString(),
|
|
627
|
-
type: 'pain_detected',
|
|
628
|
-
data: {
|
|
629
|
-
painId: observerPainId,
|
|
630
|
-
painType: 'user_frustration',
|
|
631
|
-
source: 'user_empathy',
|
|
632
|
-
reason: `Accumulated GFI (${freshGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Verified by Empathy Observer.`,
|
|
633
|
-
score: freshGfiPainScore,
|
|
634
|
-
sessionId,
|
|
635
|
-
agentId: 'main',
|
|
636
|
-
provenance: 'openclaw_context_bound',
|
|
637
|
-
evidence,
|
|
638
|
-
},
|
|
639
|
-
}, { recordObservability: false });
|
|
640
|
-
}
|
|
641
|
-
catch (emitErr) {
|
|
642
|
-
logger?.error?.(`[PD:Empathy] Pipeline FAILED to emit observer-triggered pain event: ${String(emitErr)}`);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
logger?.info?.(`[PD:Empathy] Pipeline: Background Empathy Observer did not detect any damage.`);
|
|
650
|
-
}
|
|
651
|
-
})
|
|
652
|
-
.catch((err) => {
|
|
653
|
-
logger?.warn?.(`[PD:Empathy] Pipeline: Background analysis failed or rejected: ${String(err)}`);
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
|
-
// Log unmatched messages periodically for coverage analysis
|
|
657
|
-
if (turnCount > 0 && turnCount % 50 === 0) {
|
|
658
|
-
const sampleMsg = latestUserMessage.substring(0, 80).replace(/\n/g, ' ');
|
|
659
|
-
logger?.debug?.(`[PD:Empathy] NO_MATCH: "${sampleMsg}" (turn ${turnCount}, keywords_in_store=${Object.keys(keywordStore.terms).length})`);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
// Periodic summary (every 100 turns)
|
|
663
|
-
if (turnCount > 0 && turnCount % 100 === 0) {
|
|
664
|
-
const s = getKeywordStoreSummary(keywordStore);
|
|
665
|
-
const highFP = s.highFalsePositiveTerms.slice(0, 5).map(t => `${t.term}(${t.falsePositiveRate.toFixed(2)})`).join(', ');
|
|
666
|
-
logger?.info?.(`[PD:Empathy] SUMMARY(turn=${turnCount}): terms=${s.totalTerms}, hits=${keywordStore.stats.totalHits}, zero_hit=${s.totalTerms - (s.seedTerms + s.discoveredTerms)}, high_fp=[${highFP}]`);
|
|
667
|
-
}
|
|
668
|
-
// Save keyword store on every match
|
|
669
|
-
if (matchResult.matched) {
|
|
670
|
-
saveKeywordStore(wctx.stateDir, keywordStore);
|
|
671
|
-
const { totalHits } = keywordStore.stats;
|
|
672
|
-
logger?.info?.(`[PD:Empathy] Keyword store saved after match: terms=${matchResult.matchedTerms.join(',')}, totalHits=${totalHits}`);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
catch (e) {
|
|
676
|
-
logger?.warn?.(`[PD:Empathy] ERROR: ${String(e)}`);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
195
|
}
|
|
196
|
+
// SignalCollectorHost 统一接管 correction + empathy 检测(spec §3.3 决策1)。
|
|
197
|
+
// 在 isAgentToAgent 解析之后调用,避免 agent-to-agent 流量被误当用户纠正(CodeRabbit #7)。
|
|
198
|
+
if (correctionUserText && sessionId && trigger === 'user' && !isAgentToAgent) {
|
|
199
|
+
getSignalCollectorHost(wctx, logger).detectSync(correctionUserText, sessionId, trigger, { referencesAssistantTurnId: correctionReferencesAssistantTurnId, turnIndex: correctionTurnIndex });
|
|
200
|
+
}
|
|
201
|
+
// 注:SignalCollectorHost.detectSync 已在上文 correction 段(:259)统一调用一次,
|
|
202
|
+
// 覆盖 correction + empathy 全部检测职责(含 lineage + turnIndex)。
|
|
203
|
+
// 此处不再重复调用,避免同一消息双重写入 user_turns 和重复触发 STRONG 分流。
|
|
680
204
|
// ──── 4. Heartbeat-specific checklist (also fires for cron-triggered sessions) ────
|
|
681
205
|
if (trigger === 'heartbeat' || trigger === 'cron') {
|
|
682
206
|
// ──── 4a. GFI Time-based Decay ────
|
|
@@ -975,51 +499,3 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
975
499
|
appendSystemContext
|
|
976
500
|
};
|
|
977
501
|
}
|
|
978
|
-
// ── Empathy Observer Hybrid Deep Analysis Helpers (Unified SDK Migration) ──
|
|
979
|
-
function scoreFromSeverityForSpec(severity, wctx) {
|
|
980
|
-
if (severity === 'severe')
|
|
981
|
-
return Number(wctx.config.get('empathy_engine.penalties.severe') ?? 40);
|
|
982
|
-
if (severity === 'moderate')
|
|
983
|
-
return Number(wctx.config.get('empathy_engine.penalties.moderate') ?? 25);
|
|
984
|
-
return Number(wctx.config.get('empathy_engine.penalties.mild') ?? 10);
|
|
985
|
-
}
|
|
986
|
-
function resolveEmpathyObserver(wctx, logger) {
|
|
987
|
-
try {
|
|
988
|
-
const loader = new WorkflowFunnelLoader(wctx.stateDir);
|
|
989
|
-
const funnel = loader.getFunnel('pd-empathy-observer');
|
|
990
|
-
const policy = funnel?.policy;
|
|
991
|
-
if (!policy || policy.runtimeKind !== 'pi-ai') {
|
|
992
|
-
logger?.debug?.('[PD:Empathy] workflows.yaml pd-empathy-observer policy not found. Falling back to environment variables.');
|
|
993
|
-
const provider = process.env.PD_EMPATHY_PROVIDER || 'anthropic';
|
|
994
|
-
const model = process.env.PD_EMPATHY_MODEL || 'anthropic/claude-3-5-sonnet';
|
|
995
|
-
const apiKeyEnv = process.env.PD_EMPATHY_API_KEY_ENV || 'ANTHROPIC_API_KEY';
|
|
996
|
-
const baseUrl = process.env.PD_EMPATHY_BASE_URL;
|
|
997
|
-
if (!process.env[apiKeyEnv]) {
|
|
998
|
-
logger?.debug?.(`[PD:Empathy] Empathy observer API key env ${apiKeyEnv} is not set. Background analysis disabled.`);
|
|
999
|
-
return null;
|
|
1000
|
-
}
|
|
1001
|
-
const adapter = new PiAiRuntimeAdapter({
|
|
1002
|
-
provider,
|
|
1003
|
-
model,
|
|
1004
|
-
apiKeyEnv,
|
|
1005
|
-
baseUrl,
|
|
1006
|
-
workspace: wctx.workspaceDir,
|
|
1007
|
-
});
|
|
1008
|
-
return new EmpathyObserver({ runtimeAdapter: adapter });
|
|
1009
|
-
}
|
|
1010
|
-
const adapter = new PiAiRuntimeAdapter({
|
|
1011
|
-
provider: String(policy.provider),
|
|
1012
|
-
model: String(policy.model),
|
|
1013
|
-
apiKeyEnv: String(policy.apiKeyEnv),
|
|
1014
|
-
maxRetries: policy.maxRetries,
|
|
1015
|
-
timeoutMs: policy.timeoutMs ?? 30_000,
|
|
1016
|
-
baseUrl: policy.baseUrl,
|
|
1017
|
-
workspace: wctx.workspaceDir,
|
|
1018
|
-
});
|
|
1019
|
-
return new EmpathyObserver({ runtimeAdapter: adapter }, { timeoutMs: policy.timeoutMs });
|
|
1020
|
-
}
|
|
1021
|
-
catch (err) {
|
|
1022
|
-
logger?.warn?.(`[PD:Empathy] Failed to resolve EmpathyObserver: ${String(err)}`);
|
|
1023
|
-
return null;
|
|
1024
|
-
}
|
|
1025
|
-
}
|