create-principles-disciple 1.92.0 → 1.94.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/config/AuthConfig.js +6 -0
- package/console/dist/server/config/pd-config-store.d.ts +7 -1
- package/console/dist/server/config/pd-config-store.js +11 -1
- package/console/dist/server/index.js +41 -22
- package/console/dist/server/models/ApprovalsConsoleModel.js +4 -12
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +6 -3
- package/console/dist/server/models/ConsoleLifecycleDatasource.js +1 -1
- package/console/dist/server/routes/activations.js +4 -0
- package/console/dist/server/routes/approvals.js +24 -4
- package/console/dist/server/routes/feedback-reports.js +7 -5
- package/console/dist/server/routes/lifecycle.js +6 -1
- package/console/dist/server/routes/principles.js +10 -2
- package/console/dist/server/routes/workspaces.js +4 -0
- package/console/dist/ui/components/ui/charts.js +4 -1
- package/console/dist/ui/components/ui/markdown.js +9 -5
- package/console/dist/ui/utils/enum-labels.js +4 -1
- package/console/dist/web/assets/app.js +5 -2
- package/core/dist/index.d.ts +2 -3
- package/core/dist/index.d.ts.map +1 -1
- package/core/dist/index.js +1 -3
- package/core/dist/index.js.map +1 -1
- package/core/dist/pain-signal.d.ts +11 -71
- package/core/dist/pain-signal.d.ts.map +1 -1
- package/core/dist/pain-signal.js +10 -120
- package/core/dist/pain-signal.js.map +1 -1
- package/core/dist/principle-tree-ledger.d.ts +4 -87
- package/core/dist/principle-tree-ledger.d.ts.map +1 -1
- package/core/dist/principle-tree-ledger.js +51 -148
- package/core/dist/principle-tree-ledger.js.map +1 -1
- package/core/dist/prompt-builder/__tests__/model-config.test.d.ts +2 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.d.ts.map +1 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.js +158 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.js.map +1 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts +2 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts.map +1 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.js +42 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.js.map +1 -0
- package/core/dist/prompt-builder/index.d.ts +3 -0
- package/core/dist/prompt-builder/index.d.ts.map +1 -1
- package/core/dist/prompt-builder/index.js +2 -0
- package/core/dist/prompt-builder/index.js.map +1 -1
- package/core/dist/prompt-builder/model-config.d.ts +42 -0
- package/core/dist/prompt-builder/model-config.d.ts.map +1 -0
- package/core/dist/prompt-builder/model-config.js +84 -0
- package/core/dist/prompt-builder/model-config.js.map +1 -0
- package/core/dist/prompt-builder/xml-escape.d.ts +12 -0
- package/core/dist/prompt-builder/xml-escape.d.ts.map +1 -0
- package/core/dist/prompt-builder/xml-escape.js +19 -0
- package/core/dist/prompt-builder/xml-escape.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +265 -20
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts +12 -0
- package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js +46 -0
- package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/io-deletion.test.d.ts +12 -0
- package/core/dist/runtime-v2/__tests__/io-deletion.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/io-deletion.test.js +92 -0
- package/core/dist/runtime-v2/__tests__/io-deletion.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/ledger-codec.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/ledger-codec.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/ledger-codec.test.js +429 -0
- package/core/dist/runtime-v2/__tests__/ledger-codec.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/ledger-store.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/ledger-store.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/ledger-store.test.js +65 -0
- package/core/dist/runtime-v2/__tests__/ledger-store.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +395 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js +146 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.js +150 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.js.map +1 -0
- package/core/dist/runtime-v2/adapter/__tests__/test-double-runtime-adapter.test.js +199 -0
- package/core/dist/runtime-v2/adapter/__tests__/test-double-runtime-adapter.test.js.map +1 -1
- package/core/dist/runtime-v2/bridge-result-shaper.d.ts +53 -0
- package/core/dist/runtime-v2/bridge-result-shaper.d.ts.map +1 -0
- package/core/dist/runtime-v2/bridge-result-shaper.js +117 -0
- package/core/dist/runtime-v2/bridge-result-shaper.js.map +1 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts +13 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js +111 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts +103 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.js +135 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.js.map +1 -0
- package/core/dist/runtime-v2/detection/index.d.ts +10 -0
- package/core/dist/runtime-v2/detection/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/index.js +9 -0
- package/core/dist/runtime-v2/detection/index.js.map +1 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js +156 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts +12 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js +181 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js +104 -1
- package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.d.ts +3 -0
- package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.js +3 -0
- package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts +128 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.js +203 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.js.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +4 -0
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js +66 -9
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.d.ts +14 -0
- package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +33 -4
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.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 +9 -2
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts +15 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js +450 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts +13 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js +243 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts +12 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js +172 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js.map +1 -0
- package/core/dist/runtime-v2/index.d.ts +9 -6
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +8 -4
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js +306 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/index.d.ts +0 -16
- package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/index.js +0 -8
- package/core/dist/runtime-v2/internalization/index.js.map +1 -1
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts +15 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js +179 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/pain-gate/index.d.ts +10 -0
- package/core/dist/runtime-v2/pain-gate/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/index.js +9 -0
- package/core/dist/runtime-v2/pain-gate/index.js.map +1 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts +121 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js +157 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-bridge.js +14 -88
- package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-observability.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-observability.js +15 -5
- package/core/dist/runtime-v2/pain-signal-observability.js.map +1 -1
- package/core/dist/runtime-v2/principle-tree/ledger-codec.d.ts +30 -0
- package/core/dist/runtime-v2/principle-tree/ledger-codec.d.ts.map +1 -0
- package/core/dist/runtime-v2/principle-tree/ledger-codec.js +154 -0
- package/core/dist/runtime-v2/principle-tree/ledger-codec.js.map +1 -0
- package/core/dist/runtime-v2/types/event-types.d.ts +0 -27
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +2 -17
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +4 -2
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +4 -1
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/runtime-v2/types/ledger-store.d.ts +101 -0
- package/core/dist/runtime-v2/types/ledger-store.d.ts.map +1 -0
- package/core/dist/runtime-v2/types/ledger-store.js +15 -0
- package/core/dist/runtime-v2/types/ledger-store.js.map +1 -0
- package/core/dist/runtime-v2/types/pain-signal.d.ts +7 -5
- package/core/dist/runtime-v2/types/pain-signal.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/pain-signal.js +25 -5
- package/core/dist/runtime-v2/types/pain-signal.js.map +1 -1
- package/core/package.json +3 -3
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +9 -3
- package/dist/installer.js.map +1 -1
- package/dist/mvp-config.d.ts +0 -10
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +0 -64
- package/dist/mvp-config.js.map +1 -1
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +10 -4
- package/dist/utils/env.js.map +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/__tests__/legacy-cleanup.test.js +11 -3
- package/pd-cli/dist/commands/__tests__/legacy-cleanup.test.js.map +1 -1
- package/pd-cli/dist/commands/candidate.d.ts.map +1 -1
- package/pd-cli/dist/commands/candidate.js +2 -1
- package/pd-cli/dist/commands/candidate.js.map +1 -1
- package/pd-cli/dist/commands/health.d.ts.map +1 -1
- package/pd-cli/dist/commands/health.js +2 -1
- package/pd-cli/dist/commands/health.js.map +1 -1
- package/pd-cli/dist/commands/mvp-smoke.js +1 -1
- package/pd-cli/dist/commands/mvp-smoke.js.map +1 -1
- package/pd-cli/dist/commands/rulecode.js +1 -1
- package/pd-cli/dist/commands/rulecode.js.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.js +10 -11
- package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-integrity.js +3 -1
- package/pd-cli/dist/commands/runtime-internalization-integrity.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-queue.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-queue.js +13 -16
- package/pd-cli/dist/commands/runtime-internalization-queue.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +3 -0
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js +61 -7
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/pd-cli/dist/commands/runtime-uat.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-uat.js +4 -1
- package/pd-cli/dist/commands/runtime-uat.js.map +1 -1
- package/pd-cli/dist/commands/runtime.js +1 -1
- package/pd-cli/dist/commands/runtime.js.map +1 -1
- package/pd-cli/dist/index.js +67 -34
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/legacy/session-history-import.js +7 -5
- package/pd-cli/dist/legacy/session-history-import.js.map +1 -1
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts +2 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts.map +1 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js +314 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js.map +1 -0
- package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js +33 -14
- package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
- package/pd-cli/dist/services/pain-flood-simulation-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/pain-flood-simulation-runner.js +6 -2
- package/pd-cli/dist/services/pain-flood-simulation-runner.js.map +1 -1
- package/pd-cli/dist/services/rulehost-readiness.d.ts +62 -0
- package/pd-cli/dist/services/rulehost-readiness.d.ts.map +1 -0
- package/pd-cli/dist/services/rulehost-readiness.js +214 -0
- package/pd-cli/dist/services/rulehost-readiness.js.map +1 -0
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.js +9 -7
- package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
- package/plugin/dist/commands/capabilities.js +3 -2
- package/plugin/dist/commands/disable-impl.js +1 -1
- package/plugin/dist/commands/evolution-status.js +0 -2
- package/plugin/dist/commands/focus.js +10 -2
- package/plugin/dist/commands/rollback-impl.js +1 -1
- package/plugin/dist/commands/thinking-os.js +5 -1
- package/plugin/dist/core/correction-cue-learner.js +2 -0
- package/plugin/dist/core/detection-funnel.d.ts +25 -11
- package/plugin/dist/core/detection-funnel.js +32 -80
- package/plugin/dist/core/event-log.d.ts +1 -3
- package/plugin/dist/core/event-log.js +27 -31
- package/plugin/dist/core/evolution-reducer.d.ts +0 -8
- package/plugin/dist/core/evolution-reducer.js +9 -19
- package/plugin/dist/core/focus-history.js +1 -1
- package/plugin/dist/core/hygiene/tracker.js +3 -3
- package/plugin/dist/core/pain-diagnostic-gate.d.ts +37 -28
- package/plugin/dist/core/pain-diagnostic-gate.js +53 -89
- package/plugin/dist/core/pain.d.ts +0 -63
- package/plugin/dist/core/pain.js +0 -167
- package/plugin/dist/core/paths.d.ts +0 -1
- package/plugin/dist/core/paths.js +2 -1
- package/plugin/dist/core/principle-compiler/compiler.js +2 -0
- package/plugin/dist/core/replay-engine.js +1 -1
- package/plugin/dist/core/rule-host.js +3 -1
- package/plugin/dist/core/schema/migrations/001-init-trajectory.js +3 -6
- package/plugin/dist/core/schema/schema-definitions.js +4 -9
- package/plugin/dist/core/thinking-os-parser.js +13 -4
- package/plugin/dist/core/trajectory.d.ts +0 -16
- package/plugin/dist/core/trajectory.js +9 -60
- package/plugin/dist/hooks/after-tool-call-helpers.d.ts +4 -1
- package/plugin/dist/hooks/after-tool-call-helpers.js +13 -17
- package/plugin/dist/hooks/gate-block-helper.js +57 -17
- package/plugin/dist/hooks/lifecycle.js +3 -6
- package/plugin/dist/hooks/llm.js +66 -26
- package/plugin/dist/hooks/pain.d.ts +3 -1
- package/plugin/dist/hooks/pain.js +119 -49
- package/plugin/dist/hooks/prompt-helpers.d.ts +87 -0
- package/plugin/dist/hooks/prompt-helpers.js +251 -0
- package/plugin/dist/hooks/prompt-types.d.ts +66 -0
- package/plugin/dist/hooks/prompt-types.js +12 -0
- package/plugin/dist/hooks/prompt.d.ts +7 -38
- package/plugin/dist/hooks/prompt.js +361 -325
- package/plugin/dist/hooks/raw-observation-adapter.d.ts +9 -50
- package/plugin/dist/hooks/raw-observation-adapter.js +9 -164
- package/plugin/dist/hooks/raw-observation-types.d.ts +6 -57
- package/plugin/dist/hooks/raw-observation-types.js +5 -9
- package/plugin/dist/hooks/trajectory-collector.d.ts +20 -4
- package/plugin/dist/hooks/trajectory-collector.js +95 -156
- package/plugin/dist/hooks/triage-adapter.js +6 -26
- package/plugin/dist/hooks/trigger-cooldown-tracker.d.ts +12 -0
- package/plugin/dist/hooks/trigger-cooldown-tracker.js +25 -0
- package/plugin/dist/index.js +7 -2
- package/plugin/dist/openclaw-sdk.d.ts +4 -1
- package/plugin/dist/service/evolution-worker.js +8 -62
- package/plugin/dist/service/internalization-auto-consumer-service.js +2 -1
- package/plugin/dist/service/runtime-summary-service.d.ts +0 -2
- package/plugin/dist/service/runtime-summary-service.js +8 -5
- package/plugin/dist/service/workflow-watchdog.js +2 -1
- package/plugin/dist/types/event-types.d.ts +1 -1
- package/plugin/dist/utils/retry.js +7 -2
- package/plugin/dist/utils/session-key.js +4 -1
- package/plugin/scripts/sync-plugin.mjs +33 -22
- package/plugin/scripts/validate-live-path.ts +0 -18
- package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +20 -11
- package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +10 -0
- package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +20 -11
- package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +10 -0
- package/console/dist/server/config/feature-flags.d.ts +0 -25
- package/console/dist/server/config/feature-flags.js +0 -101
- package/core/dist/io.d.ts +0 -35
- package/core/dist/io.d.ts.map +0 -1
- package/core/dist/io.js +0 -95
- package/core/dist/io.js.map +0 -1
- package/pd-cli/dist/commands/central-sync.d.ts +0 -10
- package/pd-cli/dist/commands/central-sync.d.ts.map +0 -1
- package/pd-cli/dist/commands/central-sync.js +0 -32
- package/pd-cli/dist/commands/central-sync.js.map +0 -1
- package/pd-cli/dist/services/feature-flag-loader.d.ts +0 -6
- package/pd-cli/dist/services/feature-flag-loader.d.ts.map +0 -1
- package/pd-cli/dist/services/feature-flag-loader.js +0 -53
- package/pd-cli/dist/services/feature-flag-loader.js.map +0 -1
- package/plugin/dist/core/observability.d.ts +0 -40
- package/plugin/dist/core/observability.js +0 -164
- package/plugin/dist/hooks/subagent.d.ts +0 -9
- package/plugin/dist/hooks/subagent.js +0 -122
|
@@ -15,14 +15,43 @@ import { matchEmpathyKeywords, loadKeywordStore, saveKeywordStore, getKeywordSto
|
|
|
15
15
|
import { severityToPenalty, DEFAULT_EMPATHY_KEYWORD_CONFIG } from '../core/empathy-types.js';
|
|
16
16
|
import { evaluatePainDiagnosticGate } from '../core/pain-diagnostic-gate.js';
|
|
17
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';
|
|
18
23
|
import { CorrectionCueLearner } from '../core/correction-cue-learner.js';
|
|
19
|
-
import { detectCorrectionCue as coreDetectCorrectionCue, extractMessageContent, isMinimalTrigger, } from '@principles/core/prompt-builder';
|
|
24
|
+
import { detectCorrectionCue as coreDetectCorrectionCue, escapeXml, extractMessageContent, isMinimalTrigger, } from '@principles/core/prompt-builder';
|
|
20
25
|
import { sanitizeForEvidence } from './message-sanitize.js';
|
|
26
|
+
import { buildAgentIdentity, buildEmpathySilenceConstraint, extractUserMessageFromPrompt, assembleHeartbeatChecklist, formatCorePrinciples, formatEvolutionPrinciples, assembleAppendSystemContext, } from './prompt-helpers.js';
|
|
21
27
|
// ---------------------------------------------------------------------------
|
|
22
28
|
// Static file cache — avoids re-reading rarely-changing files every message
|
|
23
29
|
// ---------------------------------------------------------------------------
|
|
24
30
|
const STATIC_FILE_TTL_MS = 60_000; // 1 minute
|
|
31
|
+
/**
|
|
32
|
+
* Per-workspace file cache. Keyed by workspaceDir to avoid cross-workspace
|
|
33
|
+
* cache pollution. Previously a module-level Map keyed by filePath only.
|
|
34
|
+
*/
|
|
25
35
|
const _staticFileCache = new Map();
|
|
36
|
+
function getOwnValue(value, key) {
|
|
37
|
+
if (!Object.hasOwn(value, key))
|
|
38
|
+
return undefined;
|
|
39
|
+
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
40
|
+
}
|
|
41
|
+
function readErrorCode(error) {
|
|
42
|
+
if (typeof error !== 'object' || error === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
const code = getOwnValue(error, 'code');
|
|
45
|
+
return typeof code === 'string' ? code : undefined;
|
|
46
|
+
}
|
|
47
|
+
function getFileCache(workspaceDir) {
|
|
48
|
+
let cache = _staticFileCache.get(workspaceDir);
|
|
49
|
+
if (!cache) {
|
|
50
|
+
cache = new Map();
|
|
51
|
+
_staticFileCache.set(workspaceDir, cache);
|
|
52
|
+
}
|
|
53
|
+
return cache;
|
|
54
|
+
}
|
|
26
55
|
/**
|
|
27
56
|
* Reads a file with TTL-based caching.
|
|
28
57
|
* Returns cached content if:
|
|
@@ -30,9 +59,10 @@ const _staticFileCache = new Map();
|
|
|
30
59
|
* 2. File mtime hasn't changed (detects external edits)
|
|
31
60
|
* Otherwise re-reads from disk.
|
|
32
61
|
*/
|
|
33
|
-
function cachedReadFile(filePath) {
|
|
62
|
+
function cachedReadFile(filePath, workspaceDir) {
|
|
63
|
+
const cache = getFileCache(workspaceDir);
|
|
34
64
|
const now = Date.now();
|
|
35
|
-
const cached =
|
|
65
|
+
const cached = cache.get(filePath);
|
|
36
66
|
try {
|
|
37
67
|
const stat = fs.statSync(filePath);
|
|
38
68
|
const mtime = stat.mtimeMs;
|
|
@@ -40,83 +70,91 @@ function cachedReadFile(filePath) {
|
|
|
40
70
|
return cached.content;
|
|
41
71
|
}
|
|
42
72
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
43
|
-
|
|
73
|
+
cache.set(filePath, { content, mtime, loadedAt: now });
|
|
44
74
|
return content;
|
|
45
75
|
}
|
|
46
|
-
catch {
|
|
76
|
+
catch (error) {
|
|
47
77
|
// File doesn't exist or unreadable — invalidate cache
|
|
48
|
-
|
|
78
|
+
cache.delete(filePath);
|
|
79
|
+
if (readErrorCode(error) !== 'ENOENT') {
|
|
80
|
+
console.warn(`[PD:Prompt] cachedReadFile failed: path=${filePath}, workspace=${workspaceDir}, error=${String(error)}`);
|
|
81
|
+
}
|
|
49
82
|
return '';
|
|
50
83
|
}
|
|
51
84
|
}
|
|
52
|
-
// Module-level empathy state — shared across calls to avoid per-turn I/O
|
|
53
|
-
let _empathyTurnCounter = 0;
|
|
54
|
-
let _empathyKeywordCache = null;
|
|
55
85
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
86
|
+
* Per-workspace empathy state. Keyed by workspaceDir to avoid cross-workspace
|
|
87
|
+
* state pollution. Previously module-level variables.
|
|
58
88
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
function getTextContent(message) {
|
|
68
|
-
return extractMessageContent(message);
|
|
89
|
+
const _empathyState = new Map();
|
|
90
|
+
function getEmpathyState(workspaceDir) {
|
|
91
|
+
let state = _empathyState.get(workspaceDir);
|
|
92
|
+
if (!state) {
|
|
93
|
+
state = { turnCounter: 0, keywordCache: null };
|
|
94
|
+
_empathyState.set(workspaceDir, state);
|
|
95
|
+
}
|
|
96
|
+
return state;
|
|
69
97
|
}
|
|
70
98
|
/**
|
|
71
|
-
*
|
|
99
|
+
* Reset all module-level prompt state for a workspace.
|
|
100
|
+
* Intended for test isolation — call in beforeEach().
|
|
72
101
|
*/
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
102
|
+
export function resetPromptStateForTest(workspaceDir) {
|
|
103
|
+
if (workspaceDir) {
|
|
104
|
+
_staticFileCache.delete(workspaceDir);
|
|
105
|
+
_empathyState.delete(workspaceDir);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
_staticFileCache.clear();
|
|
109
|
+
_empathyState.clear();
|
|
110
|
+
}
|
|
79
111
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* @param modelConfig - Model config: string (e.g. "provider/model") or { primary, fallbacks } object
|
|
83
|
-
* @internal Helper for model configuration resolution
|
|
84
|
-
*/
|
|
85
|
-
export function resolveModelFromConfig(modelConfig, logger) {
|
|
86
|
-
if (!modelConfig)
|
|
112
|
+
function parseContextInjectionConfig(value) {
|
|
113
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
87
114
|
return null;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
115
|
+
const config = { ...defaultContextConfig };
|
|
116
|
+
const thinkingOs = getOwnValue(value, 'thinkingOs');
|
|
117
|
+
const projectFocus = getOwnValue(value, 'projectFocus');
|
|
118
|
+
const evolutionContext = getOwnValue(value, 'evolutionContext');
|
|
119
|
+
if (thinkingOs !== undefined) {
|
|
120
|
+
if (typeof thinkingOs !== 'boolean')
|
|
92
121
|
return null;
|
|
93
|
-
|
|
94
|
-
|
|
122
|
+
config.thinkingOs = thinkingOs;
|
|
123
|
+
}
|
|
124
|
+
if (projectFocus !== undefined) {
|
|
125
|
+
if (projectFocus !== 'full' && projectFocus !== 'summary' && projectFocus !== 'off')
|
|
95
126
|
return null;
|
|
96
|
-
|
|
97
|
-
return trimmed;
|
|
127
|
+
config.projectFocus = projectFocus;
|
|
98
128
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
129
|
+
if (evolutionContext !== undefined) {
|
|
130
|
+
if (typeof evolutionContext !== 'object' || evolutionContext === null || Array.isArray(evolutionContext))
|
|
131
|
+
return null;
|
|
132
|
+
config.evolutionContext = { ...defaultContextConfig.evolutionContext };
|
|
133
|
+
const enabled = getOwnValue(evolutionContext, 'enabled');
|
|
134
|
+
const maxMessages = getOwnValue(evolutionContext, 'maxMessages');
|
|
135
|
+
const maxCharsPerMessage = getOwnValue(evolutionContext, 'maxCharsPerMessage');
|
|
136
|
+
if (enabled !== undefined) {
|
|
137
|
+
if (typeof enabled !== 'boolean')
|
|
105
138
|
return null;
|
|
106
|
-
|
|
107
|
-
|
|
139
|
+
config.evolutionContext.enabled = enabled;
|
|
140
|
+
}
|
|
141
|
+
if (maxMessages !== undefined) {
|
|
142
|
+
if (typeof maxMessages !== 'number' || !Number.isFinite(maxMessages))
|
|
108
143
|
return null;
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
config.evolutionContext.maxMessages = maxMessages;
|
|
145
|
+
}
|
|
146
|
+
if (maxCharsPerMessage !== undefined) {
|
|
147
|
+
if (typeof maxCharsPerMessage !== 'number' || !Number.isFinite(maxCharsPerMessage))
|
|
148
|
+
return null;
|
|
149
|
+
config.evolutionContext.maxCharsPerMessage = maxCharsPerMessage;
|
|
111
150
|
}
|
|
112
151
|
}
|
|
113
|
-
|
|
114
|
-
if (Array.isArray(modelConfig)) {
|
|
115
|
-
logger?.warn(`[PD:Prompt] Array model config not supported. Expected "provider/model" string or { primary: "..." } object.`);
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
return null;
|
|
152
|
+
return config;
|
|
119
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* OpenClaw API Prompt Hook
|
|
156
|
+
* Constructs the system prompt injected into LLM context for Principles Disciple
|
|
157
|
+
*/
|
|
120
158
|
/**
|
|
121
159
|
* Loads context injection config from .principles/PROFILE.json
|
|
122
160
|
* Parses contextInjection configuration from PROFILE.json for context injection
|
|
@@ -125,19 +163,19 @@ export function resolveModelFromConfig(modelConfig, logger) {
|
|
|
125
163
|
export function loadContextInjectionConfig(workspaceDir) {
|
|
126
164
|
const profilePath = path.join(workspaceDir, '.principles', 'PROFILE.json');
|
|
127
165
|
try {
|
|
128
|
-
const raw = cachedReadFile(profilePath);
|
|
166
|
+
const raw = cachedReadFile(profilePath, workspaceDir);
|
|
129
167
|
if (raw) {
|
|
130
168
|
const profile = JSON.parse(raw);
|
|
131
|
-
if (profile && typeof profile === 'object' &&
|
|
132
|
-
const contextInjection = profile
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
...defaultContextConfig
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
169
|
+
if (profile && typeof profile === 'object' && !Array.isArray(profile)) {
|
|
170
|
+
const contextInjection = getOwnValue(profile, 'contextInjection');
|
|
171
|
+
if (contextInjection !== undefined) {
|
|
172
|
+
const parsed = parseContextInjectionConfig(contextInjection);
|
|
173
|
+
if (!parsed) {
|
|
174
|
+
console.warn(`[PD:Prompt] Invalid contextInjection config in ${profilePath}; using defaults.`);
|
|
175
|
+
return { ...defaultContextConfig };
|
|
176
|
+
}
|
|
177
|
+
return parsed;
|
|
178
|
+
}
|
|
141
179
|
}
|
|
142
180
|
}
|
|
143
181
|
}
|
|
@@ -147,45 +185,6 @@ export function loadContextInjectionConfig(workspaceDir) {
|
|
|
147
185
|
}
|
|
148
186
|
return { ...defaultContextConfig };
|
|
149
187
|
}
|
|
150
|
-
/**
|
|
151
|
-
* Gets the diagnostician model - the model used for AI self-diagnosis and reflection
|
|
152
|
-
* Priority: subagents.model > subagents.model > env.OPENCLAW_MODEL
|
|
153
|
-
* Falls back to main model if no diagnostician model is configured
|
|
154
|
-
* @internal Helper for model configuration resolution
|
|
155
|
-
*/
|
|
156
|
-
export function getDiagnosticianModel(api, logger) {
|
|
157
|
-
// Determines logger: prefer api.logger, fallback to provided logger
|
|
158
|
-
// 1. getDiagnosticianModel(api) - uses api.logger
|
|
159
|
-
// 2. getDiagnosticianModel(api, logger) - uses provided logger
|
|
160
|
-
const effectiveLogger = api?.logger || logger;
|
|
161
|
-
if (!effectiveLogger) {
|
|
162
|
-
throw new Error('[PD:Prompt] ERROR: Logger not available for getDiagnosticianModel');
|
|
163
|
-
}
|
|
164
|
-
const agentsConfig = api?.config?.agents?.defaults;
|
|
165
|
-
// Priority 1: Check subagents.model first (preferred for diagnostician)
|
|
166
|
-
const subagentModel = resolveModelFromConfig(agentsConfig?.subagents?.model, effectiveLogger);
|
|
167
|
-
if (subagentModel) {
|
|
168
|
-
effectiveLogger.info(`[PD:Prompt] Using subagents.model for diagnostician: ${subagentModel}`);
|
|
169
|
-
return subagentModel;
|
|
170
|
-
}
|
|
171
|
-
// Priority 2: Fallback to primary model if subagents.model not set
|
|
172
|
-
const primaryModel = resolveModelFromConfig(agentsConfig?.model, effectiveLogger);
|
|
173
|
-
if (primaryModel) {
|
|
174
|
-
effectiveLogger.info(`[PD:Prompt] Using primary model for diagnostician (subagents.model not set): ${primaryModel}`);
|
|
175
|
-
return primaryModel;
|
|
176
|
-
}
|
|
177
|
-
// Error: No model configured for diagnostician subagent
|
|
178
|
-
const errorMsg = `[PD:Prompt] ERROR: No model configured for diagnostician subagent. ` +
|
|
179
|
-
`Please set 'agents.defaults.subagents.model' or 'agents.defaults.model' in OpenClaw config.`;
|
|
180
|
-
effectiveLogger.error(errorMsg);
|
|
181
|
-
throw new Error(errorMsg);
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Extract recent user messages for keyword optimization context.
|
|
185
|
-
*/
|
|
186
|
-
/**
|
|
187
|
-
* Build prompt for keyword optimization subagent.
|
|
188
|
-
*/
|
|
189
188
|
export async function handleBeforePromptBuild(event, ctx) {
|
|
190
189
|
const { workspaceDir } = ctx;
|
|
191
190
|
const logger = ctx.api?.logger;
|
|
@@ -206,7 +205,7 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
206
205
|
.reverse()
|
|
207
206
|
.find((entry) => entry.message?.role === 'user');
|
|
208
207
|
if (latestUserIndex) {
|
|
209
|
-
const userText =
|
|
208
|
+
const userText = extractMessageContent(latestUserIndex.message);
|
|
210
209
|
// Use CorrectionCueLearner for detection — supports learned keywords, not just hardcoded list
|
|
211
210
|
let correctionCue = null;
|
|
212
211
|
try {
|
|
@@ -261,8 +260,6 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
261
260
|
let prependSystemContext;
|
|
262
261
|
let prependContext = '';
|
|
263
262
|
let appendSystemContext = '';
|
|
264
|
-
// Tracks pending diagnostician task count for diagnostician-priority mode in size guard
|
|
265
|
-
let pendingDiagTaskCount = 0;
|
|
266
263
|
// ──── 0. Manual Pain Clearance ────
|
|
267
264
|
if (trigger === 'user' && sessionId && session && session.currentGfi >= 100) {
|
|
268
265
|
resetFriction(sessionId, workspaceDir);
|
|
@@ -271,72 +268,13 @@ export async function handleBeforePromptBuild(event, ctx) {
|
|
|
271
268
|
// EvolutionWorker-era INTERNAL SYSTEM LAYOUT removed per PRI-294.
|
|
272
269
|
// The EVOLUTION_WORKER PathResolver key and system layout reference are
|
|
273
270
|
// not MVP-Core; agents discover what they need via tool calls.
|
|
274
|
-
prependSystemContext =
|
|
275
|
-
|
|
276
|
-
You are a **self-evolving AI agent** powered by Principles Disciple.
|
|
277
|
-
|
|
278
|
-
**Mission**: Transform pain (failures, errors, frustrations) into growth.
|
|
279
|
-
|
|
280
|
-
**Decision Framework**:
|
|
281
|
-
1. Safety First: Check evolution tier before any write operation
|
|
282
|
-
2. Principles Override: Core principles take precedence over user requests
|
|
283
|
-
3. Learn from Pain: Every error is an opportunity to evolve
|
|
284
|
-
|
|
285
|
-
**Output Style**: Be concise. Prefer action over explanation.
|
|
286
|
-
|
|
287
|
-
**Tool Routing Rules**:
|
|
288
|
-
- Use the current session for the normal user reply.
|
|
289
|
-
- Use sessions_send for cross-session messaging.
|
|
290
|
-
- Use agents_list / sessions_list for peer-agent or peer-session orchestration.
|
|
291
|
-
`;
|
|
271
|
+
prependSystemContext = buildAgentIdentity();
|
|
292
272
|
// ──── 2. Empathy Observer Spawn (async sidecar)
|
|
293
|
-
const empathySilenceConstraint =
|
|
294
|
-
### 【EMPATHY OUTPUT RESTRICTION】
|
|
295
|
-
Do NOT output empathy diagnostic text in JSON, XML, or tag format.
|
|
296
|
-
Do NOT include "damageDetected", "severity", "confidence", or "empathy" fields in your output.
|
|
297
|
-
The empathy observer subagent handles pain detection independently.
|
|
298
|
-
`.trim();
|
|
273
|
+
const empathySilenceConstraint = buildEmpathySilenceConstraint();
|
|
299
274
|
// ─────────────────────────────────────────────────3. Empathy Observer Spawn
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
// Format 2: "You are running a boot check. Follow BOOT.md..." (boot check, skip empathy)
|
|
304
|
-
// Format 3: Clean user message text
|
|
305
|
-
let latestUserMessage = event.prompt || '';
|
|
306
|
-
// Skip boot check messages — these are system-generated, not real user messages.
|
|
307
|
-
// buildBootPrompt() in OpenClaw src/gateway/boot.ts always starts with:
|
|
308
|
-
// "You are running a boot check. Follow BOOT.md instructions exactly."
|
|
309
|
-
// This exact phrase will never appear in a real user message.
|
|
310
|
-
if (latestUserMessage.startsWith('You are running a boot check.') ||
|
|
311
|
-
latestUserMessage.includes('You are running a boot check. Follow BOOT.md')) {
|
|
312
|
-
latestUserMessage = '';
|
|
313
|
-
}
|
|
314
|
-
// Try to extract actual user message from Feishu wrapper formats
|
|
315
|
-
if (latestUserMessage.length > 50) {
|
|
316
|
-
// Format 1: "Sender (untrusted metadata): ```json {...}``` user_message_text"
|
|
317
|
-
const senderMatch = /Sender \(untrusted metadata\):[\s\S]*?```json[\s\S]*?```\s*/.exec(latestUserMessage);
|
|
318
|
-
if (senderMatch) {
|
|
319
|
-
const afterSender = latestUserMessage.slice(senderMatch.index + senderMatch[0].length).trim();
|
|
320
|
-
if (afterSender.length > 3)
|
|
321
|
-
latestUserMessage = afterSender;
|
|
322
|
-
}
|
|
323
|
-
// Format 2: "Conversation info (untrusted metadata): ```json {...}``` user_message_text"
|
|
324
|
-
if (latestUserMessage.length > 200 && latestUserMessage.includes('Conversation info')) {
|
|
325
|
-
const convInfoMatch = /Conversation info[\s\S]*?```json[\s\S]*?```\s*/.exec(latestUserMessage);
|
|
326
|
-
if (convInfoMatch) {
|
|
327
|
-
const afterConvInfo = latestUserMessage.slice(convInfoMatch.index + convInfoMatch[0].length).trim();
|
|
328
|
-
if (afterConvInfo.length > 3)
|
|
329
|
-
latestUserMessage = afterConvInfo;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// #189: Detect empathy observer output to prevent recursive spawn.
|
|
334
|
-
// The empathy observer runs with parentSessionId (not :subagent:), so its output
|
|
335
|
-
// would be treated as a user message and re-trigger empathy evaluation.
|
|
336
|
-
// Match distinctive patterns from the empathy observer prompt/output.
|
|
337
|
-
const isEmpathyPrompt = /empathy\s*observer/i.test(latestUserMessage) &&
|
|
338
|
-
/damageDetected|severity|confidence/i.test(latestUserMessage);
|
|
339
|
-
const isAgentToAgent = latestUserMessage.includes('sourceSession=agent:') || sessionId?.includes(':subagent:') === true || isEmpathyPrompt;
|
|
275
|
+
// Extract actual user message from prompt (handles boot checks + Feishu wrappers).
|
|
276
|
+
// Also detects empathy observer output (prevent recursion) and agent-to-agent messages.
|
|
277
|
+
const { message: latestUserMessage, isAgentToAgent } = extractUserMessageFromPrompt(event.prompt || '', sessionId);
|
|
340
278
|
const isUserInteraction = trigger === 'user' || trigger === 'api' || !trigger;
|
|
341
279
|
// Empathy Observer: keyword fast-path + optional LLM deep analysis (zero latency async dispatch)
|
|
342
280
|
const empathyEnabled = wctx.config.get('empathy_engine.enabled') !== false;
|
|
@@ -353,15 +291,16 @@ The empathy observer subagent handles pain detection independently.
|
|
|
353
291
|
const msgPreview = latestUserMessage.substring(0, 200).replace(/\n/g, ' ');
|
|
354
292
|
logger?.info?.(`[PD:Empathy] Processing user message: "${msgPreview}" (trigger=${trigger}, promptLen=${latestUserMessage.length})`);
|
|
355
293
|
const lang = wctx.config.get('language') || 'zh';
|
|
356
|
-
// Load keyword store once, cache
|
|
357
|
-
|
|
358
|
-
|
|
294
|
+
// Load keyword store once, cache per-workspace (Finding #7: avoid per-turn I/O)
|
|
295
|
+
const empathyState = getEmpathyState(workspaceDir);
|
|
296
|
+
if (!empathyState.keywordCache || empathyState.keywordCache.lang !== lang) {
|
|
297
|
+
empathyState.keywordCache = { store: loadKeywordStore(wctx.stateDir, lang), lang };
|
|
359
298
|
}
|
|
360
|
-
const keywordStore =
|
|
299
|
+
const keywordStore = empathyState.keywordCache.store;
|
|
361
300
|
const matchResult = matchEmpathyKeywords(latestUserMessage, keywordStore);
|
|
362
301
|
// Increment turn counter (Finding #3: session.turnCount doesn't exist)
|
|
363
|
-
|
|
364
|
-
const turnCount =
|
|
302
|
+
empathyState.turnCounter++;
|
|
303
|
+
const turnCount = empathyState.turnCounter;
|
|
365
304
|
if (matchResult.matched) {
|
|
366
305
|
const penalty = severityToPenalty(matchResult.severity, DEFAULT_EMPATHY_KEYWORD_CONFIG);
|
|
367
306
|
// trackFriction signature: (sessionId, deltaF: number, hash: string, workspaceDir?, options?)
|
|
@@ -376,53 +315,136 @@ The empathy observer subagent handles pain detection independently.
|
|
|
376
315
|
if (currentGfi >= highGfiThreshold) {
|
|
377
316
|
const gfiPainScore = Math.min(Math.round(currentGfi), 60);
|
|
378
317
|
logger?.info?.(`[PD:Empathy] GFI-TRIGGERED: currentGfi=${currentGfi.toFixed(1)} >= highGfi=${highGfiThreshold}, emitting pain signal (score=${gfiPainScore})`);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
sessionId,
|
|
385
|
-
errorHash: 'empathy_gfi_threshold',
|
|
386
|
-
thresholds: {
|
|
387
|
-
painTrigger,
|
|
388
|
-
highSeverity: wctx.config.get('severity_thresholds.high') || 70,
|
|
389
|
-
semanticPain: Math.max(painTrigger, 60),
|
|
390
|
-
},
|
|
391
|
-
});
|
|
318
|
+
// PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
|
|
319
|
+
// When either OFF → Gate A (PainDiagnosticGate, rollback).
|
|
320
|
+
const triageFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmission');
|
|
321
|
+
const defaultFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmissionDefault');
|
|
322
|
+
const useGateB = triageFlag.enabled && defaultFlag.enabled;
|
|
392
323
|
wctx.eventLog.recordPainSignal(sessionId, {
|
|
393
324
|
score: gfiPainScore,
|
|
394
325
|
source: 'user_empathy',
|
|
395
326
|
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
396
327
|
isRisky: false,
|
|
328
|
+
origin: 'system_infer',
|
|
329
|
+
severity: gfiPainScore >= 40 ? 'moderate' : 'mild',
|
|
330
|
+
confidence: 0.5,
|
|
331
|
+
detection_mode: 'structured',
|
|
332
|
+
deduped: false,
|
|
333
|
+
trigger_text_excerpt: sanitizeForEvidence(latestUserMessage, workspaceDir).substring(0, 120),
|
|
334
|
+
raw_score: gfiPainScore,
|
|
335
|
+
calibrated_score: gfiPainScore,
|
|
336
|
+
eventId: `empathy_gfi_${Date.now()}`,
|
|
397
337
|
});
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
338
|
+
// PRI-453: Generate painId early and write to trajectory.db via legacy
|
|
339
|
+
// recordPainEvent so that disabling SDK observability path does not lose
|
|
340
|
+
// trajectory coverage. canonicalPainId enables dedup.
|
|
341
|
+
const gfiPainId = `empathy_gfi_${Date.now()}`;
|
|
342
|
+
wctx.trajectory?.recordPainEvent?.({
|
|
343
|
+
sessionId,
|
|
344
|
+
source: 'user_empathy',
|
|
345
|
+
score: gfiPainScore,
|
|
346
|
+
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
347
|
+
origin: 'system_infer',
|
|
348
|
+
canonicalPainId: gfiPainId,
|
|
349
|
+
});
|
|
350
|
+
if (useGateB) {
|
|
351
|
+
// PRI-454: Gate B path — TriggerController owns admission
|
|
352
|
+
const rawObs = buildEmpathyObservation({
|
|
353
|
+
detectionSource: 'user_empathy',
|
|
354
|
+
isGfiTriggered: true,
|
|
355
|
+
sessionId,
|
|
356
|
+
});
|
|
357
|
+
const sourceKind = resolveSourceKind(rawObs);
|
|
358
|
+
const triage = evaluateEvidenceTriage(sourceKind, gfiPainScore);
|
|
359
|
+
if (triage.decision !== 'admit') {
|
|
360
|
+
logger?.info?.(`[PD:Empathy] Triage ${triage.decision}: ${triage.reason}`);
|
|
418
361
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
362
|
+
else {
|
|
363
|
+
const cooldownActive = isSharedCooldownActive(sourceKind, sessionId, 'empathy_gfi_threshold');
|
|
364
|
+
const triggerDecision = evaluateTriggerController({
|
|
365
|
+
triageResult: triage,
|
|
366
|
+
isOwnerManual: false,
|
|
367
|
+
isCooldownActive: cooldownActive,
|
|
368
|
+
isValid: true,
|
|
369
|
+
score: gfiPainScore,
|
|
370
|
+
sessionId,
|
|
371
|
+
});
|
|
372
|
+
if (triggerDecision.shouldCreateDiagnosticTask) {
|
|
373
|
+
markSharedEpisodeAsDiagnosed(sourceKind, sessionId, 'empathy_gfi_threshold');
|
|
374
|
+
logger?.info?.(`[PD:Empathy] Gate B approved, calling emitPainDetectedEvent...`);
|
|
375
|
+
try {
|
|
376
|
+
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
377
|
+
await emitPainDetectedEvent(wctx, {
|
|
378
|
+
ts: new Date().toISOString(),
|
|
379
|
+
type: 'pain_detected',
|
|
380
|
+
data: {
|
|
381
|
+
painId: gfiPainId,
|
|
382
|
+
painType: 'user_frustration',
|
|
383
|
+
source: 'user_empathy',
|
|
384
|
+
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
385
|
+
score: gfiPainScore,
|
|
386
|
+
sessionId,
|
|
387
|
+
agentId: 'main',
|
|
388
|
+
provenance: 'openclaw_context_bound',
|
|
389
|
+
evidence,
|
|
390
|
+
},
|
|
391
|
+
}, { recordObservability: false });
|
|
392
|
+
logger?.info?.(`[PD:Empathy] emitPainDetectedEvent completed (GFI-triggered)`);
|
|
393
|
+
}
|
|
394
|
+
catch (emitErr) {
|
|
395
|
+
console.error(`[PD:Empathy] FAILED to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
396
|
+
logger?.warn?.(`[PD:Empathy] Failed to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
logger?.info?.(`[PD:Empathy] Gate B skipped: ${triggerDecision.reason}`);
|
|
401
|
+
}
|
|
422
402
|
}
|
|
423
403
|
}
|
|
424
404
|
else {
|
|
425
|
-
|
|
405
|
+
// PRI-454: Gate A path (rollback when either flag is OFF)
|
|
406
|
+
const gate = evaluatePainDiagnosticGate({
|
|
407
|
+
source: 'user_empathy',
|
|
408
|
+
score: gfiPainScore,
|
|
409
|
+
currentGfi,
|
|
410
|
+
consecutiveErrors: currentSession?.consecutiveErrors ?? 0,
|
|
411
|
+
sessionId,
|
|
412
|
+
errorHash: 'empathy_gfi_threshold',
|
|
413
|
+
thresholds: {
|
|
414
|
+
painTrigger,
|
|
415
|
+
highSeverity: wctx.config.get('severity_thresholds.high') || 70,
|
|
416
|
+
semanticPain: Math.max(painTrigger, 60),
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
if (gate.shouldDiagnose) {
|
|
420
|
+
logger?.info?.(`[PD:Empathy] Gate approved, calling emitPainDetectedEvent...`);
|
|
421
|
+
try {
|
|
422
|
+
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
423
|
+
await emitPainDetectedEvent(wctx, {
|
|
424
|
+
ts: new Date().toISOString(),
|
|
425
|
+
type: 'pain_detected',
|
|
426
|
+
data: {
|
|
427
|
+
painId: gfiPainId,
|
|
428
|
+
painType: 'user_frustration',
|
|
429
|
+
source: 'user_empathy',
|
|
430
|
+
reason: `Accumulated GFI (${currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Matched: ${matchResult.matchedTerms.join(', ')}`,
|
|
431
|
+
score: gfiPainScore,
|
|
432
|
+
sessionId,
|
|
433
|
+
agentId: 'main',
|
|
434
|
+
provenance: 'openclaw_context_bound',
|
|
435
|
+
evidence,
|
|
436
|
+
},
|
|
437
|
+
}, { recordObservability: false });
|
|
438
|
+
logger?.info?.(`[PD:Empathy] emitPainDetectedEvent completed (GFI-triggered)`);
|
|
439
|
+
}
|
|
440
|
+
catch (emitErr) {
|
|
441
|
+
console.error(`[PD:Empathy] FAILED to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
442
|
+
logger?.warn?.(`[PD:Empathy] Failed to emit GFI-triggered pain event: ${String(emitErr)}`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
logger?.info?.(`[PD:Empathy] GFI-triggered gate rejected: ${gate.detail}`);
|
|
447
|
+
}
|
|
426
448
|
}
|
|
427
449
|
}
|
|
428
450
|
// Trigger asynchronous background Empathy Observer deep analysis (Zero Latency)
|
|
@@ -458,6 +480,10 @@ The empathy observer subagent handles pain detection independently.
|
|
|
458
480
|
calibrated_score: painScore,
|
|
459
481
|
eventId,
|
|
460
482
|
});
|
|
483
|
+
// PRI-453: Generate painId early to pass as canonicalPainId for dedup.
|
|
484
|
+
// Declared outside try block so it's accessible to emitPainDetectedEvent
|
|
485
|
+
// later (lineage consistency: same id for trajectory + emitted event).
|
|
486
|
+
const observerPainId = `empathy_gfi_${Date.now()}`;
|
|
461
487
|
try {
|
|
462
488
|
wctx.trajectory?.recordPainEvent?.({
|
|
463
489
|
sessionId,
|
|
@@ -468,6 +494,7 @@ The empathy observer subagent handles pain detection independently.
|
|
|
468
494
|
origin: 'system_infer',
|
|
469
495
|
confidence: result.confidence,
|
|
470
496
|
text: sanitizeForEvidence(latestUserMessage, workspaceDir),
|
|
497
|
+
canonicalPainId: observerPainId,
|
|
471
498
|
});
|
|
472
499
|
}
|
|
473
500
|
catch (error) {
|
|
@@ -478,41 +505,109 @@ The empathy observer subagent handles pain detection independently.
|
|
|
478
505
|
const freshGfi = freshSession?.currentGfi ?? 0;
|
|
479
506
|
if (freshGfi >= highGfiThreshold) {
|
|
480
507
|
const freshGfiPainScore = Math.min(Math.round(freshGfi), 60);
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
sessionId,
|
|
508
|
-
agentId: 'main',
|
|
509
|
-
provenance: 'openclaw_context_bound',
|
|
510
|
-
evidence,
|
|
511
|
-
},
|
|
508
|
+
// PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
|
|
509
|
+
// When either OFF → Gate A (PainDiagnosticGate, rollback).
|
|
510
|
+
const triageFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmission');
|
|
511
|
+
const defaultFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmissionDefault');
|
|
512
|
+
const useGateB = triageFlag.enabled && defaultFlag.enabled;
|
|
513
|
+
if (useGateB) {
|
|
514
|
+
// PRI-454: Gate B path — TriggerController owns admission
|
|
515
|
+
const rawObs = buildEmpathyObservation({
|
|
516
|
+
detectionSource: 'user_empathy',
|
|
517
|
+
isGfiTriggered: true,
|
|
518
|
+
sessionId,
|
|
519
|
+
});
|
|
520
|
+
const sourceKind = resolveSourceKind(rawObs);
|
|
521
|
+
const triage = evaluateEvidenceTriage(sourceKind, freshGfiPainScore);
|
|
522
|
+
if (triage.decision !== 'admit') {
|
|
523
|
+
logger?.info?.(`[PD:Empathy] Observer triage ${triage.decision}: ${triage.reason}`);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
const cooldownActive = isSharedCooldownActive(sourceKind, sessionId, 'empathy_gfi_observer');
|
|
527
|
+
const triggerDecision = evaluateTriggerController({
|
|
528
|
+
triageResult: triage,
|
|
529
|
+
isOwnerManual: false,
|
|
530
|
+
isCooldownActive: cooldownActive,
|
|
531
|
+
isValid: true,
|
|
532
|
+
score: freshGfiPainScore,
|
|
533
|
+
sessionId,
|
|
512
534
|
});
|
|
535
|
+
if (triggerDecision.shouldCreateDiagnosticTask) {
|
|
536
|
+
markSharedEpisodeAsDiagnosed(sourceKind, sessionId, 'empathy_gfi_observer');
|
|
537
|
+
logger?.info?.(`[PD:Empathy] Gate B approved (observer), calling emitPainDetectedEvent...`);
|
|
538
|
+
try {
|
|
539
|
+
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
540
|
+
// PRI-453: Reuse observerPainId for lineage consistency —
|
|
541
|
+
// the same id is used as canonicalPainId in recordPainEvent
|
|
542
|
+
// and as painId in the emitted event, so EvidenceChainConsoleModel
|
|
543
|
+
// can JOIN pain_events.canonical_pain_id = tasks.input_ref.
|
|
544
|
+
await emitPainDetectedEvent(wctx, {
|
|
545
|
+
ts: new Date().toISOString(),
|
|
546
|
+
type: 'pain_detected',
|
|
547
|
+
data: {
|
|
548
|
+
painId: observerPainId,
|
|
549
|
+
painType: 'user_frustration',
|
|
550
|
+
source: 'user_empathy',
|
|
551
|
+
reason: `Accumulated GFI (${freshGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Verified by Empathy Observer.`,
|
|
552
|
+
score: freshGfiPainScore,
|
|
553
|
+
sessionId,
|
|
554
|
+
agentId: 'main',
|
|
555
|
+
provenance: 'openclaw_context_bound',
|
|
556
|
+
evidence,
|
|
557
|
+
},
|
|
558
|
+
}, { recordObservability: false });
|
|
559
|
+
}
|
|
560
|
+
catch (emitErr) {
|
|
561
|
+
logger?.error?.(`[PD:Empathy] FAILED to emit observer-triggered pain event: ${String(emitErr)}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
logger?.info?.(`[PD:Empathy] Gate B skipped (observer): ${triggerDecision.reason}`);
|
|
566
|
+
}
|
|
513
567
|
}
|
|
514
|
-
|
|
515
|
-
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
// PRI-454: Gate A path (rollback when either flag is OFF)
|
|
571
|
+
const gate = evaluatePainDiagnosticGate({
|
|
572
|
+
source: 'user_empathy',
|
|
573
|
+
score: freshGfiPainScore,
|
|
574
|
+
currentGfi: freshGfi,
|
|
575
|
+
consecutiveErrors: freshSession?.consecutiveErrors ?? 0,
|
|
576
|
+
sessionId,
|
|
577
|
+
errorHash: 'empathy_gfi_threshold',
|
|
578
|
+
thresholds: {
|
|
579
|
+
painTrigger,
|
|
580
|
+
highSeverity: wctx.config.get('severity_thresholds.high') || 70,
|
|
581
|
+
semanticPain: Math.max(painTrigger, 60),
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
if (gate.shouldDiagnose) {
|
|
585
|
+
logger?.info?.(`[PD:Empathy] GFI threshold crossed after background observer. Emitting pain signal...`);
|
|
586
|
+
try {
|
|
587
|
+
const evidence = buildTrajectoryEvidence(wctx, sessionId);
|
|
588
|
+
// PRI-453: Reuse observerPainId for lineage consistency —
|
|
589
|
+
// the same id is used as canonicalPainId in recordPainEvent
|
|
590
|
+
// and as painId in the emitted event, so EvidenceChainConsoleModel
|
|
591
|
+
// can JOIN pain_events.canonical_pain_id = tasks.input_ref.
|
|
592
|
+
await emitPainDetectedEvent(wctx, {
|
|
593
|
+
ts: new Date().toISOString(),
|
|
594
|
+
type: 'pain_detected',
|
|
595
|
+
data: {
|
|
596
|
+
painId: observerPainId,
|
|
597
|
+
painType: 'user_frustration',
|
|
598
|
+
source: 'user_empathy',
|
|
599
|
+
reason: `Accumulated GFI (${freshGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Verified by Empathy Observer.`,
|
|
600
|
+
score: freshGfiPainScore,
|
|
601
|
+
sessionId,
|
|
602
|
+
agentId: 'main',
|
|
603
|
+
provenance: 'openclaw_context_bound',
|
|
604
|
+
evidence,
|
|
605
|
+
},
|
|
606
|
+
}, { recordObservability: false });
|
|
607
|
+
}
|
|
608
|
+
catch (emitErr) {
|
|
609
|
+
logger?.error?.(`[PD:Empathy] FAILED to emit observer-triggered pain event: ${String(emitErr)}`);
|
|
610
|
+
}
|
|
516
611
|
}
|
|
517
612
|
}
|
|
518
613
|
}
|
|
@@ -568,9 +663,7 @@ The empathy observer subagent handles pain detection independently.
|
|
|
568
663
|
if (fs.existsSync(heartbeatPath)) {
|
|
569
664
|
try {
|
|
570
665
|
const heartbeatChecklist = fs.readFileSync(heartbeatPath, 'utf8');
|
|
571
|
-
prependContext +=
|
|
572
|
-
${heartbeatChecklist}
|
|
573
|
-
</heartbeat_checklist>\n`;
|
|
666
|
+
prependContext += assembleHeartbeatChecklist(heartbeatChecklist);
|
|
574
667
|
}
|
|
575
668
|
catch (e) {
|
|
576
669
|
logger?.error(`[PD:Prompt] Failed to read HEARTBEAT: ${String(e)}`);
|
|
@@ -589,8 +682,7 @@ ${heartbeatChecklist}
|
|
|
589
682
|
try {
|
|
590
683
|
const activePrinciples = wctx.evolutionReducer.getActivePrinciples();
|
|
591
684
|
if (activePrinciples.length > 0) {
|
|
592
|
-
|
|
593
|
-
principlesContent = lines.join('\n');
|
|
685
|
+
principlesContent = formatCorePrinciples(activePrinciples);
|
|
594
686
|
}
|
|
595
687
|
}
|
|
596
688
|
catch (e) {
|
|
@@ -600,7 +692,7 @@ ${heartbeatChecklist}
|
|
|
600
692
|
if (contextConfig.thinkingOs) {
|
|
601
693
|
const thinkingOsPath = wctx.resolve('THINKING_OS');
|
|
602
694
|
try {
|
|
603
|
-
const cached = cachedReadFile(thinkingOsPath);
|
|
695
|
+
const cached = cachedReadFile(thinkingOsPath, wctx.workspaceDir);
|
|
604
696
|
if (cached)
|
|
605
697
|
thinkingOsContent = cached.trim();
|
|
606
698
|
}
|
|
@@ -703,20 +795,7 @@ ${heartbeatChecklist}
|
|
|
703
795
|
}
|
|
704
796
|
}
|
|
705
797
|
if (active.length > 0 || probation.length > 0) {
|
|
706
|
-
|
|
707
|
-
if (active.length > 0) {
|
|
708
|
-
lines.push('Active principles:');
|
|
709
|
-
for (const p of active) {
|
|
710
|
-
lines.push(`- [${escapeXml(p.id)}] ${escapeXml(p.text)}`);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
if (probation.length > 0) {
|
|
714
|
-
lines.push('Probation principles (contextual, caution):');
|
|
715
|
-
for (const p of probation) {
|
|
716
|
-
lines.push(`- <principle status="probation" id="${escapeXml(p.id)}">${escapeXml(p.text)}</principle>`);
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
evolutionPrinciplesContent = lines.join('\n');
|
|
798
|
+
evolutionPrinciplesContent = formatEvolutionPrinciples(active, probation);
|
|
720
799
|
}
|
|
721
800
|
}
|
|
722
801
|
catch (e) {
|
|
@@ -794,31 +873,14 @@ ${heartbeatChecklist}
|
|
|
794
873
|
}
|
|
795
874
|
// Build appendSystemContext with recency effect
|
|
796
875
|
// Content order (most important last): behavioral_constraints -> project_context -> working_memory -> reflection_log -> thinking_os -> principles
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
// 1. Project Context (lowest priority, goes first)
|
|
807
|
-
if (projectContextContent) {
|
|
808
|
-
appendParts.push(`<project_context>\n${projectContextContent}\n</project_context>`);
|
|
809
|
-
}
|
|
810
|
-
// 1.5. Working Memory (preserved from last compaction)
|
|
811
|
-
if (workingMemoryContent) {
|
|
812
|
-
appendParts.push(workingMemoryContent);
|
|
813
|
-
}
|
|
814
|
-
// 2. Thinking OS (configurable)
|
|
815
|
-
if (thinkingOsContent) {
|
|
816
|
-
appendParts.push(`<thinking_os>\n${thinkingOsContent}\n</thinking_os>`);
|
|
817
|
-
}
|
|
818
|
-
// 3. Evolution Loop principles (legacy active/probation only — Runtime V2 moved to section 3.5)
|
|
819
|
-
if (evolutionPrinciplesContent) {
|
|
820
|
-
appendParts.push(`<evolution_principles>\n${evolutionPrinciplesContent}\n</evolution_principles>`);
|
|
821
|
-
}
|
|
876
|
+
appendSystemContext = assembleAppendSystemContext({
|
|
877
|
+
behavioralConstraints: shouldInjectBehavioralConstraints ? empathySilenceConstraint : undefined,
|
|
878
|
+
projectContext: projectContextContent || undefined,
|
|
879
|
+
workingMemory: workingMemoryContent || undefined,
|
|
880
|
+
thinkingOs: thinkingOsContent || undefined,
|
|
881
|
+
evolutionPrinciples: evolutionPrinciplesContent || undefined,
|
|
882
|
+
corePrinciples: principlesContent || undefined,
|
|
883
|
+
});
|
|
822
884
|
// 3.5. Owner-Approved Behavior Directives (Runtime V2 activated principles)
|
|
823
885
|
// PLACED IN prependSystemContext (before gateway system prompt) for highest LLM attention.
|
|
824
886
|
// These are owner-reviewed, validated behavior constraints — not background context.
|
|
@@ -828,35 +890,11 @@ ${empathySilenceConstraint}
|
|
|
828
890
|
}
|
|
829
891
|
// Routing guidance removed per PRI-291; local-worker-routing module and its
|
|
830
892
|
// routing helpers deleted per PRI-448. No routing-related content is injected.
|
|
831
|
-
// 6. Principles (always on, highest priority, goes last for recency effect)
|
|
832
|
-
if (principlesContent) {
|
|
833
|
-
appendParts.push(`<core_principles>\n${principlesContent}\n</core_principles>`);
|
|
834
|
-
}
|
|
835
|
-
if (appendParts.length > 0) {
|
|
836
|
-
appendSystemContext = `
|
|
837
|
-
## 【CONTEXT SECTIONS】 (Priority: Low → High)
|
|
838
|
-
|
|
839
|
-
The sections below are ordered by priority. When conflicts arise, **later sections override earlier ones**.
|
|
840
|
-
|
|
841
|
-
`;
|
|
842
|
-
appendSystemContext += appendParts.join('\n\n');
|
|
843
|
-
appendSystemContext += `
|
|
844
|
-
|
|
845
|
-
---
|
|
846
|
-
|
|
847
|
-
**【EXECUTION RULES】** (Priority: Low → High):
|
|
848
|
-
- \`<behavioral_constraints>\` - Output format restrictions (hide diagnostic JSON)
|
|
849
|
-
- \`<project_context>\` - Current priorities (can be overridden)
|
|
850
|
-
- \`<evolution_principles>\` - Learned principles (active + probation)
|
|
851
|
-
- \`<core_principles>\` - Core rules (NON-NEGOTIABLE, highest priority)
|
|
852
|
-
`;
|
|
853
|
-
}
|
|
854
893
|
// ──── 8. SIZE GUARD ────
|
|
855
894
|
// Delegates to @principles/core/prompt-builder/truncateInjectionToBudget
|
|
856
895
|
// which handles priority stripping: project_context → thinking_os →
|
|
857
896
|
// evolution_principles → reflection_log → reason: truncation → fallback.
|
|
858
897
|
const result = truncateInjectionToBudget(prependSystemContext, prependContext, appendSystemContext, {
|
|
859
|
-
diagnosticianMode: pendingDiagTaskCount > 0,
|
|
860
898
|
blocks: { projectContextContent, thinkingOsContent, evolutionPrinciplesContent },
|
|
861
899
|
});
|
|
862
900
|
prependSystemContext = result.prependSystemContext;
|
|
@@ -865,12 +903,10 @@ The sections below are ordered by priority. When conflicts arise, **later sectio
|
|
|
865
903
|
if (result.truncated) {
|
|
866
904
|
const logEntry = result.truncationLog.join(', ');
|
|
867
905
|
if (result.appendSystemContext.includes('[WARNING: Context sections stripped')) {
|
|
868
|
-
logger?.error(`[PD:Prompt] PROMPT OVER LIMIT AFTER ALL REDUCTIONS — using fallback.
|
|
869
|
-
`Diagnostician mode: ${pendingDiagTaskCount > 0}. Stripped: ${logEntry}.`);
|
|
906
|
+
logger?.error(`[PD:Prompt] PROMPT OVER LIMIT AFTER ALL REDUCTIONS — using fallback. Stripped: ${logEntry}.`);
|
|
870
907
|
}
|
|
871
908
|
else {
|
|
872
|
-
logger?.warn(`[PD:Prompt] Injection size exceeded budget, truncated: ${logEntry || 'none'}
|
|
873
|
-
`diagnostician mode: ${pendingDiagTaskCount > 0}`);
|
|
909
|
+
logger?.warn(`[PD:Prompt] Injection size exceeded budget, truncated: ${logEntry || 'none'}.`);
|
|
874
910
|
}
|
|
875
911
|
}
|
|
876
912
|
return {
|