principles-disciple 1.8.1 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADVANCED_CONFIG_ZH.md +97 -0
- package/AGENT_INSTALL.md +173 -0
- package/AGENT_INSTALL_EN.md +173 -0
- package/INSTALL.md +256 -0
- package/SKILL.md +63 -0
- package/docs/COMMAND_REFERENCE.md +76 -0
- package/docs/COMMAND_REFERENCE_EN.md +79 -0
- package/esbuild.config.js +75 -0
- package/openclaw.plugin.json +4 -4
- package/package.json +11 -13
- package/scripts/build-web.mjs +46 -0
- package/scripts/install-dependencies.cjs +47 -0
- package/scripts/sync-plugin.mjs +802 -0
- package/scripts/verify-build.mjs +109 -0
- package/src/agents/nocturnal-dreamer.md +152 -0
- package/src/agents/nocturnal-philosopher.md +138 -0
- package/src/agents/nocturnal-reflector.md +126 -0
- package/src/agents/nocturnal-scribe.md +164 -0
- package/src/commands/capabilities.ts +85 -0
- package/{dist/commands/context.js → src/commands/context.ts} +78 -38
- package/src/commands/evolution-status.ts +146 -0
- package/src/commands/export.ts +111 -0
- package/src/commands/focus.ts +533 -0
- package/src/commands/nocturnal-review.ts +311 -0
- package/src/commands/nocturnal-rollout.ts +763 -0
- package/src/commands/nocturnal-train.ts +1002 -0
- package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
- package/src/commands/principle-rollback.ts +27 -0
- package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
- package/src/commands/samples.ts +60 -0
- package/src/commands/strategy.ts +38 -0
- package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
- package/src/commands/workflow-debug.ts +128 -0
- package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
- package/src/config/errors.ts +163 -0
- package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
- package/src/constants/diagnostician.ts +66 -0
- package/src/constants/tools.ts +62 -0
- package/src/core/adaptive-thresholds.ts +476 -0
- package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
- package/{dist/core/config.js → src/core/config.ts} +158 -46
- package/src/core/control-ui-db.ts +435 -0
- package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
- package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
- package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
- package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
- package/src/core/empathy-keyword-matcher.ts +327 -0
- package/src/core/empathy-types.ts +218 -0
- package/src/core/event-log.ts +544 -0
- package/src/core/evolution-engine.ts +612 -0
- package/src/core/evolution-logger.ts +353 -0
- package/src/core/evolution-migration.ts +77 -0
- package/src/core/evolution-reducer.ts +731 -0
- package/src/core/evolution-types.ts +456 -0
- package/src/core/external-training-contract.ts +527 -0
- package/src/core/focus-history.ts +1458 -0
- package/src/core/hygiene/tracker.ts +117 -0
- package/{dist/core/init.js → src/core/init.ts} +39 -26
- package/src/core/local-worker-routing.ts +617 -0
- package/{dist/core/migration.js → src/core/migration.ts} +18 -11
- package/src/core/model-deployment-registry.ts +722 -0
- package/src/core/model-training-registry.ts +813 -0
- package/src/core/nocturnal-arbiter.ts +706 -0
- package/src/core/nocturnal-candidate-scoring.ts +392 -0
- package/src/core/nocturnal-compliance.ts +1075 -0
- package/src/core/nocturnal-dataset.ts +668 -0
- package/src/core/nocturnal-executability.ts +428 -0
- package/src/core/nocturnal-export.ts +390 -0
- package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
- package/src/core/nocturnal-trajectory-extractor.ts +484 -0
- package/src/core/nocturnal-trinity.ts +1384 -0
- package/src/core/pain.ts +122 -0
- package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
- package/{dist/core/paths.js → src/core/paths.ts} +13 -4
- package/src/core/principle-training-state.ts +450 -0
- package/src/core/profile.ts +226 -0
- package/src/core/promotion-gate.ts +822 -0
- package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
- package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +175 -62
- package/src/core/shadow-observation-registry.ts +534 -0
- package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
- package/src/core/thinking-models.ts +217 -0
- package/src/core/training-program.ts +630 -0
- package/src/core/trajectory-types.ts +243 -0
- package/src/core/trajectory.ts +1673 -0
- package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
- package/src/hooks/bash-risk.ts +171 -0
- package/src/hooks/edit-verification.ts +295 -0
- package/src/hooks/gate-block-helper.ts +160 -0
- package/src/hooks/gate.ts +210 -0
- package/src/hooks/gfi-gate.ts +177 -0
- package/src/hooks/lifecycle.ts +326 -0
- package/{dist/hooks/llm.js → src/hooks/llm.ts} +160 -80
- package/src/hooks/message-sanitize.ts +45 -0
- package/src/hooks/pain.ts +384 -0
- package/src/hooks/progressive-trust-gate.ts +174 -0
- package/src/hooks/prompt.ts +920 -0
- package/src/hooks/subagent.ts +207 -0
- package/src/hooks/thinking-checkpoint.ts +73 -0
- package/src/hooks/trajectory-collector.ts +290 -0
- package/src/http/principles-console-route.ts +716 -0
- package/src/i18n/commands.ts +117 -0
- package/src/index.ts +694 -0
- package/src/service/central-database.ts +831 -0
- package/src/service/control-ui-query-service.ts +888 -0
- package/src/service/evolution-query-service.ts +405 -0
- package/src/service/evolution-worker.ts +1646 -0
- package/src/service/health-query-service.ts +836 -0
- package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +235 -79
- package/src/service/nocturnal-service.ts +1015 -0
- package/src/service/nocturnal-target-selector.ts +532 -0
- package/src/service/phase3-input-filter.ts +237 -0
- package/src/service/runtime-summary-service.ts +757 -0
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
- package/{dist/service/subagent-workflow/empathy-observer-workflow-manager.js → src/service/subagent-workflow/empathy-observer-workflow-manager.ts} +240 -117
- package/src/service/subagent-workflow/index.ts +51 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
- package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
- package/{dist/service/subagent-workflow/types.d.ts → src/service/subagent-workflow/types.ts} +137 -18
- package/src/service/subagent-workflow/workflow-store.ts +328 -0
- package/src/service/trajectory-service.ts +15 -0
- package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
- package/src/tools/deep-reflect.ts +349 -0
- package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
- package/src/types/event-types.ts +453 -0
- package/src/types/hygiene-types.ts +31 -0
- package/src/types/principle-tree-schema.ts +244 -0
- package/src/types/runtime-summary.ts +49 -0
- package/src/types.ts +74 -0
- package/src/utils/file-lock.ts +391 -0
- package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
- package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
- package/src/utils/io.ts +110 -0
- package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
- package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
- package/src/utils/subagent-probe.ts +94 -0
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
- package/templates/pain_settings.json +2 -1
- package/tests/README.md +120 -0
- package/tests/build-artifacts.test.ts +111 -0
- package/tests/commands/evolution-status.test.ts +222 -0
- package/tests/commands/evolver.test.ts +22 -0
- package/tests/commands/export.test.ts +78 -0
- package/tests/commands/nocturnal-review.test.ts +448 -0
- package/tests/commands/nocturnal-train.test.ts +97 -0
- package/tests/commands/pain.test.ts +108 -0
- package/tests/commands/samples.test.ts +65 -0
- package/tests/commands/strategy.test.ts +34 -0
- package/tests/commands/thinking-os.test.ts +88 -0
- package/tests/core/adaptive-thresholds.test.ts +261 -0
- package/tests/core/config-service.test.ts +89 -0
- package/tests/core/config.test.ts +90 -0
- package/tests/core/control-ui-db.test.ts +75 -0
- package/tests/core/core-template-guidance.test.ts +21 -0
- package/tests/core/detection-funnel.test.ts +63 -0
- package/tests/core/detection-service.test.ts +50 -0
- package/tests/core/dictionary-service.test.ts +116 -0
- package/tests/core/dictionary.test.ts +168 -0
- package/tests/core/empathy-keyword-matcher.test.ts +209 -0
- package/tests/core/event-log.test.ts +181 -0
- package/tests/core/evolution-e2e.test.ts +58 -0
- package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
- package/tests/core/evolution-engine.test.ts +562 -0
- package/tests/core/evolution-logger.test.ts +148 -0
- package/tests/core/evolution-migration.test.ts +50 -0
- package/tests/core/evolution-paths.test.ts +21 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
- package/tests/core/evolution-reducer.test.ts +180 -0
- package/tests/core/evolution-types-loop.test.ts +48 -0
- package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
- package/tests/core/external-training-contract.test.ts +463 -0
- package/tests/core/focus-history.test.ts +682 -0
- package/tests/core/init-flatten.test.ts +69 -0
- package/tests/core/init-refactor.test.ts +87 -0
- package/tests/core/init-v1.3.test.ts +46 -0
- package/tests/core/init.test.ts +190 -0
- package/tests/core/local-worker-routing.test.ts +757 -0
- package/tests/core/migration.test.ts +84 -0
- package/tests/core/model-deployment-registry.test.ts +845 -0
- package/tests/core/model-training-registry.test.ts +889 -0
- package/tests/core/nocturnal-arbiter.test.ts +494 -0
- package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
- package/tests/core/nocturnal-compliance.test.ts +646 -0
- package/tests/core/nocturnal-dataset.test.ts +892 -0
- package/tests/core/nocturnal-executability.test.ts +357 -0
- package/tests/core/nocturnal-export.test.ts +462 -0
- package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
- package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
- package/tests/core/nocturnal-trinity.test.ts +953 -0
- package/tests/core/pain.test.ts +33 -0
- package/tests/core/path-resolver.test.ts +57 -0
- package/tests/core/paths-refactor.test.ts +42 -0
- package/tests/core/phase7-rollout-integration.test.ts +477 -0
- package/tests/core/principle-training-state.test.ts +712 -0
- package/tests/core/profile.test.ts +56 -0
- package/tests/core/promotion-gate.test.ts +556 -0
- package/tests/core/risk-calculator.test.ts +168 -0
- package/tests/core/session-tracker.test.ts +191 -0
- package/tests/core/training-program.test.ts +472 -0
- package/tests/core/trajectory.test.ts +265 -0
- package/tests/core/workspace-context-factory.test.ts +18 -0
- package/tests/core/workspace-context.test.ts +134 -0
- package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
- package/tests/fixtures/production-compatibility.test.ts +147 -0
- package/tests/fixtures/production-mock-generator.ts +282 -0
- package/tests/hooks/bash-risk-integration.test.ts +137 -0
- package/tests/hooks/bash-risk.test.ts +81 -0
- package/tests/hooks/edit-verification.test.ts +678 -0
- package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
- package/tests/hooks/gate-edit-verification.test.ts +435 -0
- package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
- package/tests/hooks/gate.test.ts +271 -0
- package/tests/hooks/gfi-gate-unit.test.ts +422 -0
- package/tests/hooks/gfi-gate.test.ts +669 -0
- package/tests/hooks/lifecycle.test.ts +248 -0
- package/tests/hooks/llm.test.ts +308 -0
- package/tests/hooks/message-sanitize.test.ts +36 -0
- package/tests/hooks/pain.test.ts +141 -0
- package/tests/hooks/progressive-trust-gate.test.ts +277 -0
- package/tests/hooks/prompt.test.ts +1411 -0
- package/tests/hooks/subagent.test.ts +467 -0
- package/tests/hooks/thinking-gate.test.ts +313 -0
- package/tests/http/principles-console-route.test.ts +140 -0
- package/tests/hygiene-tracker.test.ts +77 -0
- package/tests/index.integration.test.ts +179 -0
- package/tests/index.shadow-routing.integration.test.ts +140 -0
- package/tests/index.test.ts +9 -0
- package/tests/integration/empathy-workflow-integration.test.ts +627 -0
- package/tests/service/control-ui-query-service.test.ts +121 -0
- package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
- package/tests/service/evolution-worker.test.ts +585 -0
- package/tests/service/nocturnal-runtime.test.ts +470 -0
- package/tests/service/nocturnal-service.test.ts +577 -0
- package/tests/service/nocturnal-target-selector.test.ts +615 -0
- package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
- package/tests/service/phase3-input-filter.test.ts +289 -0
- package/tests/service/runtime-summary-service.test.ts +919 -0
- package/tests/task-compliance.test.ts +166 -0
- package/tests/test-utils.ts +48 -0
- package/tests/tools/critique-prompt.test.ts +260 -0
- package/tests/tools/deep-reflect.test.ts +232 -0
- package/tests/tools/model-index.test.ts +246 -0
- package/tests/ui/app.test.tsx +114 -0
- package/tests/utils/file-lock.test.ts +407 -0
- package/tests/utils/hashing.test.ts +32 -0
- package/tests/utils/io.test.ts +39 -0
- package/tests/utils/nlp.test.ts +53 -0
- package/tests/utils/plugin-logger.test.ts +156 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/ui/src/App.tsx +45 -0
- package/ui/src/api.ts +216 -0
- package/ui/src/charts.tsx +586 -0
- package/ui/src/components/ErrorState.tsx +6 -0
- package/ui/src/components/Loading.tsx +13 -0
- package/ui/src/components/ProtectedRoute.tsx +12 -0
- package/ui/src/components/Shell.tsx +91 -0
- package/ui/src/components/WorkspaceConfig.tsx +146 -0
- package/ui/src/components/index.ts +5 -0
- package/ui/src/context/auth.tsx +80 -0
- package/ui/src/context/theme.tsx +66 -0
- package/ui/src/hooks/useAutoRefresh.ts +39 -0
- package/ui/src/i18n/ui.ts +363 -0
- package/ui/src/main.tsx +16 -0
- package/ui/src/pages/EvolutionPage.tsx +352 -0
- package/ui/src/pages/FeedbackPage.tsx +140 -0
- package/ui/src/pages/GateMonitorPage.tsx +136 -0
- package/ui/src/pages/LoginPage.tsx +88 -0
- package/ui/src/pages/OverviewPage.tsx +238 -0
- package/ui/src/pages/SamplesPage.tsx +174 -0
- package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
- package/ui/src/styles.css +1661 -0
- package/ui/src/types.ts +368 -0
- package/ui/src/utils/format.ts +15 -0
- package/vitest.config.ts +23 -0
- package/dist/commands/capabilities.d.ts +0 -3
- package/dist/commands/capabilities.js +0 -73
- package/dist/commands/context.d.ts +0 -5
- package/dist/commands/evolution-status.d.ts +0 -4
- package/dist/commands/evolution-status.js +0 -117
- package/dist/commands/evolver.d.ts +0 -9
- package/dist/commands/evolver.js +0 -26
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -98
- package/dist/commands/focus.d.ts +0 -14
- package/dist/commands/focus.js +0 -457
- package/dist/commands/nocturnal-review.d.ts +0 -24
- package/dist/commands/nocturnal-review.js +0 -265
- package/dist/commands/nocturnal-rollout.d.ts +0 -27
- package/dist/commands/nocturnal-rollout.js +0 -671
- package/dist/commands/nocturnal-train.d.ts +0 -25
- package/dist/commands/nocturnal-train.js +0 -919
- package/dist/commands/pain.d.ts +0 -5
- package/dist/commands/principle-rollback.d.ts +0 -4
- package/dist/commands/principle-rollback.js +0 -22
- package/dist/commands/rollback.d.ts +0 -19
- package/dist/commands/samples.d.ts +0 -2
- package/dist/commands/samples.js +0 -55
- package/dist/commands/strategy.d.ts +0 -3
- package/dist/commands/strategy.js +0 -29
- package/dist/commands/thinking-os.d.ts +0 -2
- package/dist/config/defaults/runtime.d.ts +0 -40
- package/dist/config/errors.d.ts +0 -84
- package/dist/config/errors.js +0 -94
- package/dist/config/index.js +0 -7
- package/dist/constants/diagnostician.d.ts +0 -12
- package/dist/constants/diagnostician.js +0 -56
- package/dist/constants/tools.d.ts +0 -17
- package/dist/constants/tools.js +0 -54
- package/dist/core/adaptive-thresholds.d.ts +0 -186
- package/dist/core/adaptive-thresholds.js +0 -300
- package/dist/core/config-service.d.ts +0 -15
- package/dist/core/config.d.ts +0 -129
- package/dist/core/control-ui-db.d.ts +0 -95
- package/dist/core/control-ui-db.js +0 -292
- package/dist/core/detection-funnel.d.ts +0 -33
- package/dist/core/detection-service.d.ts +0 -15
- package/dist/core/dictionary-service.d.ts +0 -15
- package/dist/core/dictionary.d.ts +0 -38
- package/dist/core/event-log.d.ts +0 -82
- package/dist/core/event-log.js +0 -463
- package/dist/core/evolution-engine.d.ts +0 -118
- package/dist/core/evolution-engine.js +0 -464
- package/dist/core/evolution-logger.d.ts +0 -137
- package/dist/core/evolution-logger.js +0 -256
- package/dist/core/evolution-migration.d.ts +0 -5
- package/dist/core/evolution-migration.js +0 -65
- package/dist/core/evolution-reducer.d.ts +0 -98
- package/dist/core/evolution-reducer.js +0 -465
- package/dist/core/evolution-types.d.ts +0 -287
- package/dist/core/evolution-types.js +0 -78
- package/dist/core/external-training-contract.d.ts +0 -276
- package/dist/core/external-training-contract.js +0 -269
- package/dist/core/focus-history.d.ts +0 -210
- package/dist/core/focus-history.js +0 -1185
- package/dist/core/hygiene/tracker.d.ts +0 -22
- package/dist/core/hygiene/tracker.js +0 -106
- package/dist/core/init.d.ts +0 -12
- package/dist/core/local-worker-routing.d.ts +0 -175
- package/dist/core/local-worker-routing.js +0 -525
- package/dist/core/migration.d.ts +0 -6
- package/dist/core/model-deployment-registry.d.ts +0 -218
- package/dist/core/model-deployment-registry.js +0 -503
- package/dist/core/model-training-registry.d.ts +0 -295
- package/dist/core/model-training-registry.js +0 -475
- package/dist/core/nocturnal-arbiter.d.ts +0 -159
- package/dist/core/nocturnal-arbiter.js +0 -534
- package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
- package/dist/core/nocturnal-candidate-scoring.js +0 -266
- package/dist/core/nocturnal-compliance.d.ts +0 -175
- package/dist/core/nocturnal-compliance.js +0 -824
- package/dist/core/nocturnal-dataset.d.ts +0 -224
- package/dist/core/nocturnal-dataset.js +0 -443
- package/dist/core/nocturnal-executability.d.ts +0 -85
- package/dist/core/nocturnal-executability.js +0 -331
- package/dist/core/nocturnal-export.d.ts +0 -124
- package/dist/core/nocturnal-export.js +0 -275
- package/dist/core/nocturnal-paths.d.ts +0 -124
- package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
- package/dist/core/nocturnal-trajectory-extractor.js +0 -307
- package/dist/core/nocturnal-trinity.d.ts +0 -311
- package/dist/core/nocturnal-trinity.js +0 -880
- package/dist/core/pain.d.ts +0 -4
- package/dist/core/pain.js +0 -70
- package/dist/core/path-resolver.d.ts +0 -46
- package/dist/core/paths.d.ts +0 -65
- package/dist/core/principle-training-state.d.ts +0 -121
- package/dist/core/principle-training-state.js +0 -321
- package/dist/core/profile.d.ts +0 -62
- package/dist/core/profile.js +0 -210
- package/dist/core/promotion-gate.d.ts +0 -238
- package/dist/core/promotion-gate.js +0 -529
- package/dist/core/risk-calculator.d.ts +0 -22
- package/dist/core/session-tracker.d.ts +0 -101
- package/dist/core/shadow-observation-registry.d.ts +0 -217
- package/dist/core/shadow-observation-registry.js +0 -308
- package/dist/core/system-logger.d.ts +0 -8
- package/dist/core/thinking-models.d.ts +0 -38
- package/dist/core/thinking-models.js +0 -170
- package/dist/core/training-program.d.ts +0 -233
- package/dist/core/training-program.js +0 -433
- package/dist/core/trajectory.d.ts +0 -411
- package/dist/core/trajectory.js +0 -1307
- package/dist/core/workspace-context.d.ts +0 -71
- package/dist/hooks/bash-risk.d.ts +0 -57
- package/dist/hooks/bash-risk.js +0 -137
- package/dist/hooks/edit-verification.d.ts +0 -62
- package/dist/hooks/edit-verification.js +0 -256
- package/dist/hooks/gate-block-helper.d.ts +0 -44
- package/dist/hooks/gate-block-helper.js +0 -119
- package/dist/hooks/gate.d.ts +0 -24
- package/dist/hooks/gate.js +0 -173
- package/dist/hooks/gfi-gate.d.ts +0 -40
- package/dist/hooks/gfi-gate.js +0 -113
- package/dist/hooks/lifecycle.d.ts +0 -5
- package/dist/hooks/lifecycle.js +0 -284
- package/dist/hooks/llm.d.ts +0 -13
- package/dist/hooks/message-sanitize.d.ts +0 -3
- package/dist/hooks/message-sanitize.js +0 -37
- package/dist/hooks/pain.d.ts +0 -5
- package/dist/hooks/pain.js +0 -301
- package/dist/hooks/progressive-trust-gate.d.ts +0 -52
- package/dist/hooks/progressive-trust-gate.js +0 -134
- package/dist/hooks/prompt.d.ts +0 -49
- package/dist/hooks/prompt.js +0 -905
- package/dist/hooks/subagent.d.ts +0 -10
- package/dist/hooks/subagent.js +0 -387
- package/dist/hooks/thinking-checkpoint.d.ts +0 -37
- package/dist/hooks/thinking-checkpoint.js +0 -51
- package/dist/hooks/trajectory-collector.d.ts +0 -32
- package/dist/hooks/trajectory-collector.js +0 -256
- package/dist/http/principles-console-route.d.ts +0 -9
- package/dist/http/principles-console-route.js +0 -681
- package/dist/i18n/commands.d.ts +0 -26
- package/dist/i18n/commands.js +0 -116
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -581
- package/dist/service/central-database.d.ts +0 -104
- package/dist/service/central-database.js +0 -649
- package/dist/service/control-ui-query-service.d.ts +0 -221
- package/dist/service/control-ui-query-service.js +0 -543
- package/dist/service/empathy-observer-manager.d.ts +0 -88
- package/dist/service/empathy-observer-manager.js +0 -414
- package/dist/service/evolution-query-service.d.ts +0 -155
- package/dist/service/evolution-query-service.js +0 -258
- package/dist/service/evolution-worker.d.ts +0 -101
- package/dist/service/evolution-worker.js +0 -975
- package/dist/service/health-query-service.d.ts +0 -170
- package/dist/service/health-query-service.js +0 -662
- package/dist/service/nocturnal-runtime.d.ts +0 -183
- package/dist/service/nocturnal-service.d.ts +0 -163
- package/dist/service/nocturnal-service.js +0 -787
- package/dist/service/nocturnal-target-selector.d.ts +0 -145
- package/dist/service/nocturnal-target-selector.js +0 -315
- package/dist/service/phase3-input-filter.d.ts +0 -73
- package/dist/service/phase3-input-filter.js +0 -172
- package/dist/service/runtime-summary-service.d.ts +0 -122
- package/dist/service/runtime-summary-service.js +0 -485
- package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +0 -48
- package/dist/service/subagent-workflow/index.d.ts +0 -4
- package/dist/service/subagent-workflow/index.js +0 -3
- package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +0 -77
- package/dist/service/subagent-workflow/runtime-direct-driver.js +0 -75
- package/dist/service/subagent-workflow/types.js +0 -11
- package/dist/service/subagent-workflow/workflow-store.d.ts +0 -26
- package/dist/service/subagent-workflow/workflow-store.js +0 -165
- package/dist/service/trajectory-service.d.ts +0 -2
- package/dist/service/trajectory-service.js +0 -15
- package/dist/tools/critique-prompt.d.ts +0 -14
- package/dist/tools/deep-reflect.d.ts +0 -39
- package/dist/tools/deep-reflect.js +0 -350
- package/dist/tools/model-index.d.ts +0 -9
- package/dist/types/event-types.d.ts +0 -306
- package/dist/types/event-types.js +0 -106
- package/dist/types/hygiene-types.d.ts +0 -20
- package/dist/types/hygiene-types.js +0 -12
- package/dist/types/runtime-summary.d.ts +0 -47
- package/dist/types/runtime-summary.js +0 -1
- package/dist/types.d.ts +0 -50
- package/dist/types.js +0 -22
- package/dist/utils/file-lock.d.ts +0 -71
- package/dist/utils/file-lock.js +0 -309
- package/dist/utils/glob-match.d.ts +0 -28
- package/dist/utils/hashing.d.ts +0 -9
- package/dist/utils/io.d.ts +0 -6
- package/dist/utils/io.js +0 -106
- package/dist/utils/nlp.d.ts +0 -9
- package/dist/utils/plugin-logger.d.ts +0 -39
- package/dist/utils/subagent-probe.d.ts +0 -34
- package/dist/utils/subagent-probe.js +0 -81
|
@@ -1,30 +1,63 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PluginLogger } from '../../openclaw-sdk.js';
|
|
2
|
+
import type {
|
|
3
|
+
WorkflowManager,
|
|
4
|
+
WorkflowHandle,
|
|
5
|
+
SubagentWorkflowSpec,
|
|
6
|
+
WorkflowMetadata,
|
|
7
|
+
WorkflowDebugSummary,
|
|
8
|
+
EmpathyObserverPayload,
|
|
9
|
+
EmpathyResult,
|
|
10
|
+
WorkflowResultContext,
|
|
11
|
+
WorkflowPersistContext,
|
|
12
|
+
} from './types.js';
|
|
13
|
+
import { RuntimeDirectDriver, type RunParams } from './runtime-direct-driver.js';
|
|
2
14
|
import { WorkflowStore } from './workflow-store.js';
|
|
3
15
|
import { isSubagentRuntimeAvailable } from '../../utils/subagent-probe.js';
|
|
4
16
|
import { WorkspaceContext } from '../../core/workspace-context.js';
|
|
5
17
|
import { trackFriction } from '../../core/session-tracker.js';
|
|
18
|
+
|
|
6
19
|
const WORKFLOW_SESSION_PREFIX = 'agent:main:subagent:workflow-';
|
|
20
|
+
|
|
7
21
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
8
22
|
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
logger;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
|
|
24
|
+
export interface EmpathyObserverWorkflowOptions {
|
|
25
|
+
workspaceDir: string;
|
|
26
|
+
logger: PluginLogger;
|
|
27
|
+
subagent: RuntimeDirectDriver['subagent'];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class EmpathyObserverWorkflowManager implements WorkflowManager {
|
|
31
|
+
private readonly store: WorkflowStore;
|
|
32
|
+
private readonly driver: RuntimeDirectDriver;
|
|
33
|
+
private readonly logger: PluginLogger;
|
|
34
|
+
private readonly workspaceDir: string;
|
|
35
|
+
|
|
36
|
+
private activeWorkflows = new Map<string, NodeJS.Timeout>();
|
|
37
|
+
private completedWorkflows = new Map<string, number>();
|
|
38
|
+
private workflowSpecs = new Map<string, SubagentWorkflowSpec<unknown>>();
|
|
39
|
+
|
|
40
|
+
constructor(opts: EmpathyObserverWorkflowOptions) {
|
|
18
41
|
this.workspaceDir = opts.workspaceDir;
|
|
19
42
|
this.logger = opts.logger;
|
|
20
43
|
this.store = new WorkflowStore({ workspaceDir: opts.workspaceDir });
|
|
21
44
|
this.driver = new RuntimeDirectDriver({ subagent: opts.subagent, logger: opts.logger });
|
|
22
45
|
}
|
|
23
|
-
|
|
46
|
+
|
|
47
|
+
async startWorkflow<TResult>(
|
|
48
|
+
spec: SubagentWorkflowSpec<TResult>,
|
|
49
|
+
options: {
|
|
50
|
+
parentSessionId: string;
|
|
51
|
+
workspaceDir?: string;
|
|
52
|
+
taskInput: unknown;
|
|
53
|
+
metadata?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
): Promise<WorkflowHandle> {
|
|
24
56
|
const workflowId = this.generateWorkflowId();
|
|
25
57
|
const childSessionKey = this.buildChildSessionKey(options.parentSessionId);
|
|
26
58
|
const now = Date.now();
|
|
27
|
-
|
|
59
|
+
|
|
60
|
+
const metadata: WorkflowMetadata = {
|
|
28
61
|
parentSessionId: options.parentSessionId,
|
|
29
62
|
workspaceDir: options.workspaceDir,
|
|
30
63
|
taskInput: options.taskInput,
|
|
@@ -32,22 +65,28 @@ export class EmpathyObserverWorkflowManager {
|
|
|
32
65
|
workflowType: spec.workflowType,
|
|
33
66
|
...options.metadata,
|
|
34
67
|
};
|
|
68
|
+
|
|
35
69
|
this.logger.info(`[PD:EmpathyObserverWorkflow] Starting workflow: workflowId=${workflowId}, type=${spec.workflowType}`);
|
|
70
|
+
|
|
36
71
|
// Surface degrade: skip boot sessions (they run outside gateway request context)
|
|
37
72
|
if (options.parentSessionId.startsWith('boot-')) {
|
|
38
73
|
this.logger.info(`[PD:EmpathyObserverWorkflow] Skipping workflow: boot session (gateway request context unavailable)`);
|
|
39
74
|
throw new Error(`EmpathyObserverWorkflowManager: cannot start workflow for boot session`);
|
|
40
75
|
}
|
|
76
|
+
|
|
41
77
|
// Surface degrade: check subagent runtime availability before calling run()
|
|
42
78
|
if (!isSubagentRuntimeAvailable(this.driver.getSubagent())) {
|
|
43
79
|
this.logger.info(`[PD:EmpathyObserverWorkflow] Skipping workflow: subagent runtime unavailable`);
|
|
44
80
|
throw new Error(`EmpathyObserverWorkflowManager: subagent runtime unavailable`);
|
|
45
81
|
}
|
|
82
|
+
|
|
46
83
|
if (spec.transport !== 'runtime_direct') {
|
|
47
84
|
throw new Error(`EmpathyObserverWorkflowManager only supports runtime_direct transport`);
|
|
48
85
|
}
|
|
86
|
+
|
|
49
87
|
const runParams = this.buildRunParams(spec, options, childSessionKey);
|
|
50
88
|
const runResult = await this.driver.run(runParams);
|
|
89
|
+
|
|
51
90
|
this.store.createWorkflow({
|
|
52
91
|
workflow_id: workflowId,
|
|
53
92
|
workflow_type: spec.workflowType,
|
|
@@ -61,8 +100,10 @@ export class EmpathyObserverWorkflowManager {
|
|
|
61
100
|
metadata_json: JSON.stringify(metadata),
|
|
62
101
|
});
|
|
63
102
|
this.store.recordEvent(workflowId, 'spawned', null, 'active', 'subagent spawned', { runId: runResult.runId });
|
|
64
|
-
this.workflowSpecs.set(workflowId, spec);
|
|
103
|
+
this.workflowSpecs.set(workflowId, spec as SubagentWorkflowSpec<unknown>);
|
|
104
|
+
|
|
65
105
|
this.scheduleWaitPoll(workflowId, spec.timeoutMs ?? DEFAULT_TIMEOUT_MS, runResult.runId);
|
|
106
|
+
|
|
66
107
|
return {
|
|
67
108
|
workflowId,
|
|
68
109
|
childSessionKey,
|
|
@@ -70,7 +111,17 @@ export class EmpathyObserverWorkflowManager {
|
|
|
70
111
|
state: 'active',
|
|
71
112
|
};
|
|
72
113
|
}
|
|
73
|
-
|
|
114
|
+
|
|
115
|
+
private buildRunParams<TResult>(
|
|
116
|
+
spec: SubagentWorkflowSpec<TResult>,
|
|
117
|
+
options: {
|
|
118
|
+
parentSessionId: string;
|
|
119
|
+
workspaceDir?: string;
|
|
120
|
+
taskInput: unknown;
|
|
121
|
+
metadata?: Record<string, unknown>;
|
|
122
|
+
},
|
|
123
|
+
childSessionKey: string
|
|
124
|
+
): RunParams {
|
|
74
125
|
const message = spec.buildPrompt(options.taskInput, {
|
|
75
126
|
parentSessionId: options.parentSessionId,
|
|
76
127
|
workspaceDir: options.workspaceDir,
|
|
@@ -79,16 +130,20 @@ export class EmpathyObserverWorkflowManager {
|
|
|
79
130
|
workflowType: spec.workflowType,
|
|
80
131
|
...(options.metadata ?? {}),
|
|
81
132
|
});
|
|
133
|
+
|
|
82
134
|
return {
|
|
83
135
|
sessionKey: childSessionKey,
|
|
84
136
|
message,
|
|
85
137
|
lane: 'subagent',
|
|
86
138
|
deliver: false,
|
|
87
|
-
idempotencyKey:
|
|
139
|
+
idempotencyKey: options.parentSessionId
|
|
140
|
+
? `${options.parentSessionId}:${Date.now()}`
|
|
141
|
+
: `pd:${childSessionKey}:${Date.now()}`,
|
|
88
142
|
expectsCompletionMessage: true,
|
|
89
143
|
};
|
|
90
144
|
}
|
|
91
|
-
|
|
145
|
+
|
|
146
|
+
static buildEmpathyPrompt(userMessage: string): string {
|
|
92
147
|
return [
|
|
93
148
|
'You are an empathy observer.',
|
|
94
149
|
'Analyze ONLY the user message and return strict JSON (no markdown):',
|
|
@@ -96,92 +151,122 @@ export class EmpathyObserverWorkflowManager {
|
|
|
96
151
|
`User message: ${JSON.stringify(userMessage.trim())}`,
|
|
97
152
|
].join('\n');
|
|
98
153
|
}
|
|
99
|
-
|
|
154
|
+
|
|
155
|
+
private scheduleWaitPoll(
|
|
156
|
+
workflowId: string,
|
|
157
|
+
timeoutMs: number,
|
|
158
|
+
runId: string
|
|
159
|
+
): void {
|
|
100
160
|
const effectiveTimeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
161
|
+
|
|
101
162
|
const timeout = setTimeout(async () => {
|
|
102
163
|
try {
|
|
103
164
|
const result = await this.driver.wait({ runId, timeoutMs: effectiveTimeoutMs });
|
|
104
165
|
await this.notifyWaitResult(workflowId, result.status, result.error);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
166
|
+
} catch (error) {
|
|
107
167
|
this.logger.error(`[PD:EmpathyObserverWorkflow] Wait poll failed: ${String(error)}`);
|
|
108
168
|
await this.notifyWaitResult(workflowId, 'error', String(error));
|
|
109
169
|
}
|
|
110
170
|
}, 100);
|
|
171
|
+
|
|
111
172
|
this.activeWorkflows.set(workflowId, timeout);
|
|
112
173
|
}
|
|
113
|
-
|
|
174
|
+
|
|
175
|
+
async notifyWaitResult(
|
|
176
|
+
workflowId: string,
|
|
177
|
+
status: 'ok' | 'error' | 'timeout',
|
|
178
|
+
error?: string
|
|
179
|
+
): Promise<void> {
|
|
114
180
|
const workflow = this.store.getWorkflow(workflowId);
|
|
115
181
|
if (!workflow) {
|
|
116
182
|
this.logger.warn(`[PD:EmpathyObserverWorkflow] notifyWaitResult: workflow not found: ${workflowId}`);
|
|
117
183
|
return;
|
|
118
184
|
}
|
|
185
|
+
|
|
119
186
|
if (workflow.state === 'completed' || workflow.state === 'terminal_error' || workflow.state === 'expired') {
|
|
120
187
|
this.logger.info(`[PD:EmpathyObserverWorkflow] notifyWaitResult: ignoring terminal workflow: ${workflowId}, state=${workflow.state}`);
|
|
121
188
|
return;
|
|
122
189
|
}
|
|
190
|
+
|
|
123
191
|
this.logger.info(`[PD:EmpathyObserverWorkflow] notifyWaitResult: workflowId=${workflowId}, status=${status}`);
|
|
192
|
+
|
|
124
193
|
const previousState = workflow.state;
|
|
125
194
|
this.store.updateWorkflowState(workflowId, 'wait_result');
|
|
126
195
|
this.store.recordEvent(workflowId, 'wait_result', previousState, 'wait_result', `wait completed: ${status}`, { error });
|
|
196
|
+
|
|
127
197
|
const spec = this.workflowSpecs.get(workflowId);
|
|
128
198
|
const shouldFinalize = spec ? spec.shouldFinalizeOnWaitStatus(status) : status === 'ok';
|
|
199
|
+
|
|
129
200
|
if (shouldFinalize) {
|
|
130
201
|
await this.finalizeOnce(workflowId);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
202
|
+
} else {
|
|
133
203
|
this.store.updateWorkflowState(workflowId, 'terminal_error');
|
|
134
204
|
this.store.recordEvent(workflowId, 'finalize_skipped', 'wait_result', 'terminal_error', `wait status: ${status}`, { error });
|
|
135
205
|
}
|
|
136
206
|
}
|
|
137
|
-
|
|
207
|
+
|
|
208
|
+
async notifyLifecycleEvent(
|
|
209
|
+
workflowId: string,
|
|
210
|
+
event: 'subagent_spawned' | 'subagent_ended',
|
|
211
|
+
data?: { outcome?: 'ok' | 'error' | 'timeout' | 'killed' | 'reset' | 'deleted'; error?: string }
|
|
212
|
+
): Promise<void> {
|
|
138
213
|
this.logger.info(`[PD:EmpathyObserverWorkflow] notifyLifecycleEvent: workflowId=${workflowId}, event=${event}`);
|
|
214
|
+
|
|
139
215
|
if (event === 'subagent_ended' && data?.outcome) {
|
|
140
216
|
await this.notifyWaitResult(workflowId, data.outcome === 'ok' ? 'ok' : data.outcome === 'error' ? 'error' : 'timeout', data.error);
|
|
141
217
|
}
|
|
142
218
|
}
|
|
143
|
-
|
|
219
|
+
|
|
220
|
+
async finalizeOnce(workflowId: string): Promise<void> {
|
|
144
221
|
const workflow = this.store.getWorkflow(workflowId);
|
|
145
222
|
if (!workflow) {
|
|
146
223
|
this.logger.warn(`[PD:EmpathyObserverWorkflow] finalizeOnce: workflow not found: ${workflowId}`);
|
|
147
224
|
return;
|
|
148
225
|
}
|
|
226
|
+
|
|
149
227
|
const spec = this.workflowSpecs.get(workflowId);
|
|
150
228
|
if (!spec) {
|
|
151
229
|
throw new Error(`Workflow spec not registered for ${workflowId}`);
|
|
152
230
|
}
|
|
231
|
+
|
|
153
232
|
if (this.isCompleted(workflowId)) {
|
|
154
233
|
this.logger.info(`[PD:EmpathyObserverWorkflow] finalizeOnce: already completed: ${workflowId}`);
|
|
155
234
|
return;
|
|
156
235
|
}
|
|
236
|
+
|
|
157
237
|
this.logger.info(`[PD:EmpathyObserverWorkflow] Finalizing workflow: ${workflowId}`);
|
|
238
|
+
|
|
158
239
|
this.store.updateWorkflowState(workflowId, 'finalizing');
|
|
240
|
+
|
|
159
241
|
try {
|
|
160
242
|
const result = await this.driver.getResult({ sessionKey: workflow.child_session_key, limit: 20 });
|
|
161
|
-
|
|
243
|
+
|
|
244
|
+
const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
|
|
162
245
|
const parsed = await spec.parseResult({
|
|
163
246
|
messages: result.messages,
|
|
164
247
|
assistantTexts: result.assistantTexts,
|
|
165
248
|
metadata,
|
|
166
249
|
waitStatus: 'ok',
|
|
167
250
|
});
|
|
251
|
+
|
|
168
252
|
if (!parsed) {
|
|
169
253
|
this.store.updateWorkflowState(workflowId, 'terminal_error');
|
|
170
254
|
this.store.recordEvent(workflowId, 'parse_failed', 'finalizing', 'terminal_error', 'spec.parseResult returned null', {});
|
|
171
255
|
return;
|
|
172
256
|
}
|
|
257
|
+
|
|
173
258
|
await spec.persistResult({
|
|
174
259
|
result: parsed,
|
|
175
260
|
metadata,
|
|
176
261
|
workspaceDir: this.workspaceDir,
|
|
177
262
|
});
|
|
178
263
|
this.store.recordEvent(workflowId, 'persisted', 'finalizing', 'finalizing', 'result persisted', {});
|
|
264
|
+
|
|
179
265
|
if (spec.shouldDeleteSessionAfterFinalize && workflow.run_id) {
|
|
180
266
|
try {
|
|
181
267
|
await this.driver.cleanup({ sessionKey: workflow.child_session_key });
|
|
182
268
|
this.store.updateCleanupState(workflowId, 'completed');
|
|
183
|
-
}
|
|
184
|
-
catch (cleanupError) {
|
|
269
|
+
} catch (cleanupError) {
|
|
185
270
|
this.logger.error(`[PD:EmpathyObserverWorkflow] cleanup failed after persistence: ${String(cleanupError)}`);
|
|
186
271
|
this.store.updateCleanupState(workflowId, 'failed');
|
|
187
272
|
this.store.updateWorkflowState(workflowId, 'cleanup_pending');
|
|
@@ -190,51 +275,74 @@ export class EmpathyObserverWorkflowManager {
|
|
|
190
275
|
return;
|
|
191
276
|
}
|
|
192
277
|
}
|
|
278
|
+
|
|
193
279
|
this.store.updateWorkflowState(workflowId, 'completed');
|
|
194
280
|
this.store.recordEvent(workflowId, 'finalized', 'finalizing', 'completed', 'success', {});
|
|
195
281
|
this.markCompleted(workflowId);
|
|
196
|
-
|
|
197
|
-
catch (error) {
|
|
282
|
+
|
|
283
|
+
} catch (error) {
|
|
198
284
|
this.logger.error(`[PD:EmpathyObserverWorkflow] finalizeOnce failed: ${String(error)}`);
|
|
199
285
|
this.store.updateWorkflowState(workflowId, 'terminal_error');
|
|
200
286
|
this.store.recordEvent(workflowId, 'finalize_error', 'finalizing', 'terminal_error', String(error), {});
|
|
201
287
|
throw error;
|
|
202
288
|
}
|
|
203
289
|
}
|
|
204
|
-
|
|
290
|
+
|
|
291
|
+
async sweepExpiredWorkflows(maxAgeMs = DEFAULT_TTL_MS): Promise<number> {
|
|
205
292
|
const expired = this.store.getExpiredWorkflows(maxAgeMs);
|
|
293
|
+
|
|
206
294
|
this.logger.info(`[PD:EmpathyObserverWorkflow] sweepExpiredWorkflows: found ${expired.length} expired`);
|
|
295
|
+
|
|
207
296
|
for (const workflow of expired) {
|
|
208
297
|
try {
|
|
209
298
|
this.logger.info(`[PD:EmpathyObserverWorkflow] Sweeping expired workflow: ${workflow.workflow_id}`);
|
|
299
|
+
|
|
210
300
|
await this.driver.cleanup({ sessionKey: workflow.child_session_key });
|
|
211
301
|
this.store.updateCleanupState(workflow.workflow_id, 'completed');
|
|
212
302
|
this.store.updateWorkflowState(workflow.workflow_id, 'expired');
|
|
213
303
|
this.store.recordEvent(workflow.workflow_id, 'swept', workflow.state, 'expired', 'TTL expired', {});
|
|
214
|
-
|
|
215
|
-
catch (error) {
|
|
304
|
+
|
|
305
|
+
} catch (error) {
|
|
216
306
|
this.logger.error(`[PD:EmpathyObserverWorkflow] Sweep cleanup failed for ${workflow.workflow_id}: ${String(error)}`);
|
|
217
307
|
this.store.updateCleanupState(workflow.workflow_id, 'failed');
|
|
218
308
|
}
|
|
219
309
|
}
|
|
310
|
+
|
|
311
|
+
// Clean up memory Maps to prevent leaks
|
|
312
|
+
const cutoff = Date.now() - 60_000; // 1 minute dedup window
|
|
313
|
+
for (const [id, timestamp] of this.completedWorkflows) {
|
|
314
|
+
if (timestamp < cutoff) {
|
|
315
|
+
this.completedWorkflows.delete(id);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const [id, timeout] of this.activeWorkflows) {
|
|
319
|
+
const wf = this.store.getWorkflow(id);
|
|
320
|
+
if (!wf || wf.state === 'expired' || wf.state === 'completed' || wf.state === 'terminal_error') {
|
|
321
|
+
clearTimeout(timeout);
|
|
322
|
+
this.activeWorkflows.delete(id);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
220
326
|
return expired.length;
|
|
221
327
|
}
|
|
222
|
-
|
|
328
|
+
|
|
329
|
+
async getWorkflowDebugSummary(workflowId: string, eventLimit = 10): Promise<WorkflowDebugSummary | null> {
|
|
223
330
|
const workflow = this.store.getWorkflow(workflowId);
|
|
224
|
-
if (!workflow)
|
|
225
|
-
|
|
226
|
-
const metadata = JSON.parse(workflow.metadata_json);
|
|
331
|
+
if (!workflow) return null;
|
|
332
|
+
|
|
333
|
+
const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
|
|
227
334
|
const recentEvents = this.store
|
|
228
335
|
.getEvents(workflowId)
|
|
229
336
|
.slice(-eventLimit)
|
|
230
337
|
.map((event) => ({
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
338
|
+
eventType: event.event_type,
|
|
339
|
+
fromState: event.from_state,
|
|
340
|
+
toState: event.to_state,
|
|
341
|
+
reason: event.reason,
|
|
342
|
+
createdAt: event.created_at,
|
|
343
|
+
payload: JSON.parse(event.payload_json || '{}') as Record<string, unknown>,
|
|
344
|
+
}));
|
|
345
|
+
|
|
238
346
|
return {
|
|
239
347
|
workflowId: workflow.workflow_id,
|
|
240
348
|
workflowType: workflow.workflow_type,
|
|
@@ -249,78 +357,82 @@ export class EmpathyObserverWorkflowManager {
|
|
|
249
357
|
recentEvents,
|
|
250
358
|
};
|
|
251
359
|
}
|
|
252
|
-
|
|
360
|
+
|
|
361
|
+
private generateWorkflowId(): string {
|
|
253
362
|
return `wf_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
254
363
|
}
|
|
255
|
-
|
|
364
|
+
|
|
365
|
+
private buildChildSessionKey(parentSessionId: string): string {
|
|
256
366
|
const safeParentSessionId = parentSessionId
|
|
257
367
|
.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
258
368
|
.substring(0, 64);
|
|
259
369
|
const timestamp = Date.now();
|
|
260
370
|
return `${WORKFLOW_SESSION_PREFIX}${safeParentSessionId}-${timestamp}`;
|
|
261
371
|
}
|
|
262
|
-
|
|
372
|
+
|
|
373
|
+
private extractAssistantText(messages: unknown[], assistantTexts?: string[]): string {
|
|
263
374
|
if (assistantTexts && assistantTexts.length > 0) {
|
|
264
375
|
return assistantTexts[assistantTexts.length - 1] || '';
|
|
265
376
|
}
|
|
377
|
+
|
|
266
378
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
267
|
-
const msg = messages[i];
|
|
268
|
-
if (msg?.role !== 'assistant')
|
|
269
|
-
|
|
270
|
-
if (typeof msg.content === 'string')
|
|
271
|
-
return msg.content;
|
|
379
|
+
const msg = messages[i] as { role?: string; content?: unknown };
|
|
380
|
+
if (msg?.role !== 'assistant') continue;
|
|
381
|
+
if (typeof msg.content === 'string') return msg.content;
|
|
272
382
|
if (Array.isArray(msg.content)) {
|
|
273
383
|
const txt = msg.content
|
|
274
|
-
.filter((part) => part?.type === 'text' && typeof part.text === 'string')
|
|
275
|
-
.map((part) => part.text)
|
|
384
|
+
.filter((part: any) => part?.type === 'text' && typeof part.text === 'string')
|
|
385
|
+
.map((part: any) => part.text)
|
|
276
386
|
.join('\n');
|
|
277
|
-
if (txt)
|
|
278
|
-
return txt;
|
|
387
|
+
if (txt) return txt;
|
|
279
388
|
}
|
|
280
389
|
}
|
|
390
|
+
|
|
281
391
|
return '';
|
|
282
392
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
393
|
+
|
|
394
|
+
parseEmpathyPayload(rawText: string): EmpathyObserverPayload | null {
|
|
395
|
+
if (!rawText?.trim()) return null;
|
|
396
|
+
|
|
286
397
|
try {
|
|
287
|
-
return JSON.parse(rawText.trim());
|
|
288
|
-
}
|
|
289
|
-
catch {
|
|
398
|
+
return JSON.parse(rawText.trim()) as EmpathyObserverPayload;
|
|
399
|
+
} catch {
|
|
290
400
|
const match = rawText.match(/\{[\s\S]*\}/);
|
|
291
401
|
if (!match) {
|
|
292
402
|
this.logger.warn('[PD:EmpathyObserverWorkflow] Observer payload is not valid JSON');
|
|
293
403
|
return null;
|
|
294
404
|
}
|
|
295
405
|
try {
|
|
296
|
-
return JSON.parse(match[0]);
|
|
297
|
-
}
|
|
298
|
-
catch {
|
|
406
|
+
return JSON.parse(match[0]) as EmpathyObserverPayload;
|
|
407
|
+
} catch {
|
|
299
408
|
this.logger.warn('[PD:EmpathyObserverWorkflow] Failed to parse observer JSON payload');
|
|
300
409
|
return null;
|
|
301
410
|
}
|
|
302
411
|
}
|
|
303
412
|
}
|
|
304
|
-
|
|
413
|
+
|
|
414
|
+
private isCompleted(workflowId: string): boolean {
|
|
305
415
|
const timestamp = this.completedWorkflows.get(workflowId);
|
|
306
|
-
if (!timestamp)
|
|
307
|
-
return false;
|
|
416
|
+
if (!timestamp) return false;
|
|
308
417
|
if (Date.now() - timestamp > 5 * 60 * 1000) {
|
|
309
418
|
this.completedWorkflows.delete(workflowId);
|
|
310
419
|
return false;
|
|
311
420
|
}
|
|
312
421
|
return true;
|
|
313
422
|
}
|
|
314
|
-
|
|
423
|
+
|
|
424
|
+
private markCompleted(workflowId: string): void {
|
|
315
425
|
this.completedWorkflows.set(workflowId, Date.now());
|
|
316
426
|
this.workflowSpecs.delete(workflowId);
|
|
427
|
+
|
|
317
428
|
const timeout = this.activeWorkflows.get(workflowId);
|
|
318
429
|
if (timeout) {
|
|
319
430
|
clearTimeout(timeout);
|
|
320
431
|
this.activeWorkflows.delete(workflowId);
|
|
321
432
|
}
|
|
322
433
|
}
|
|
323
|
-
|
|
434
|
+
|
|
435
|
+
dispose(): void {
|
|
324
436
|
for (const timeout of this.activeWorkflows.values()) {
|
|
325
437
|
clearTimeout(timeout);
|
|
326
438
|
}
|
|
@@ -328,93 +440,91 @@ export class EmpathyObserverWorkflowManager {
|
|
|
328
440
|
this.store.dispose();
|
|
329
441
|
}
|
|
330
442
|
}
|
|
331
|
-
|
|
443
|
+
|
|
444
|
+
export function createEmpathyObserverWorkflowManager(
|
|
445
|
+
opts: EmpathyObserverWorkflowOptions
|
|
446
|
+
): EmpathyObserverWorkflowManager {
|
|
332
447
|
return new EmpathyObserverWorkflowManager(opts);
|
|
333
448
|
}
|
|
449
|
+
|
|
334
450
|
/**
|
|
335
451
|
* Extract raw assistant text from messages or assistantTexts array.
|
|
336
452
|
*/
|
|
337
|
-
function extractAssistantTextForSpec(messages, assistantTexts) {
|
|
453
|
+
function extractAssistantTextForSpec(messages: unknown[], assistantTexts?: string[]): string {
|
|
338
454
|
if (assistantTexts && assistantTexts.length > 0) {
|
|
339
455
|
return assistantTexts[assistantTexts.length - 1] || '';
|
|
340
456
|
}
|
|
341
457
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
342
|
-
const msg = messages[i];
|
|
343
|
-
if (msg?.role !== 'assistant')
|
|
344
|
-
|
|
345
|
-
if (typeof msg.content === 'string')
|
|
346
|
-
return msg.content;
|
|
458
|
+
const msg = messages[i] as { role?: string; content?: unknown };
|
|
459
|
+
if (msg?.role !== 'assistant') continue;
|
|
460
|
+
if (typeof msg.content === 'string') return msg.content;
|
|
347
461
|
if (Array.isArray(msg.content)) {
|
|
348
462
|
const txt = msg.content
|
|
349
|
-
.filter((part) => part?.type === 'text' && typeof part.text === 'string')
|
|
350
|
-
.map((part) => part.text)
|
|
463
|
+
.filter((part: any) => part?.type === 'text' && typeof part.text === 'string')
|
|
464
|
+
.map((part: any) => part.text)
|
|
351
465
|
.join('\n');
|
|
352
|
-
if (txt)
|
|
353
|
-
return txt;
|
|
466
|
+
if (txt) return txt;
|
|
354
467
|
}
|
|
355
468
|
}
|
|
356
469
|
return '';
|
|
357
470
|
}
|
|
471
|
+
|
|
358
472
|
/**
|
|
359
473
|
* Parse empathy observer JSON payload from raw text.
|
|
360
474
|
*/
|
|
361
|
-
function parseEmpathyPayloadForSpec(rawText) {
|
|
362
|
-
if (!rawText?.trim())
|
|
363
|
-
return null;
|
|
475
|
+
function parseEmpathyPayloadForSpec(rawText: string): EmpathyObserverPayload | null {
|
|
476
|
+
if (!rawText?.trim()) return null;
|
|
364
477
|
try {
|
|
365
|
-
return JSON.parse(rawText.trim());
|
|
366
|
-
}
|
|
367
|
-
catch {
|
|
478
|
+
return JSON.parse(rawText.trim()) as EmpathyObserverPayload;
|
|
479
|
+
} catch {
|
|
368
480
|
const match = rawText.match(/\{[\s\S]*\}/);
|
|
369
|
-
if (!match)
|
|
370
|
-
return null;
|
|
481
|
+
if (!match) return null;
|
|
371
482
|
try {
|
|
372
|
-
return JSON.parse(match[0]);
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
483
|
+
return JSON.parse(match[0]) as EmpathyObserverPayload;
|
|
484
|
+
} catch {
|
|
375
485
|
return null;
|
|
376
486
|
}
|
|
377
487
|
}
|
|
378
488
|
}
|
|
489
|
+
|
|
379
490
|
/**
|
|
380
491
|
* Normalize severity to valid enum.
|
|
381
492
|
*/
|
|
382
|
-
function normalizeSeverityForSpec(severity) {
|
|
383
|
-
if (severity === 'severe')
|
|
384
|
-
|
|
385
|
-
if (severity === 'moderate')
|
|
386
|
-
return 'moderate';
|
|
493
|
+
function normalizeSeverityForSpec(severity: string | undefined): 'mild' | 'moderate' | 'severe' {
|
|
494
|
+
if (severity === 'severe') return 'severe';
|
|
495
|
+
if (severity === 'moderate') return 'moderate';
|
|
387
496
|
return 'mild';
|
|
388
497
|
}
|
|
498
|
+
|
|
389
499
|
/**
|
|
390
500
|
* Normalize confidence to [0, 1] range.
|
|
391
501
|
*/
|
|
392
|
-
function normalizeConfidenceForSpec(value) {
|
|
393
|
-
if (!Number.isFinite(value))
|
|
394
|
-
return 1;
|
|
502
|
+
function normalizeConfidenceForSpec(value: number | undefined): number {
|
|
503
|
+
if (!Number.isFinite(value)) return 1;
|
|
395
504
|
return Math.max(0, Math.min(1, Number(value)));
|
|
396
505
|
}
|
|
506
|
+
|
|
397
507
|
/**
|
|
398
508
|
* Calculate pain score from severity using config.
|
|
399
509
|
*/
|
|
400
|
-
function scoreFromSeverityForSpec(severity, wctx) {
|
|
401
|
-
if (severity === 'severe')
|
|
402
|
-
|
|
403
|
-
if (severity === 'moderate')
|
|
404
|
-
return Number(wctx.config.get('empathy_engine.penalties.moderate') ?? 25);
|
|
510
|
+
function scoreFromSeverityForSpec(severity: string | undefined, wctx: WorkspaceContext): number {
|
|
511
|
+
if (severity === 'severe') return Number(wctx.config.get('empathy_engine.penalties.severe') ?? 40);
|
|
512
|
+
if (severity === 'moderate') return Number(wctx.config.get('empathy_engine.penalties.moderate') ?? 25);
|
|
405
513
|
return Number(wctx.config.get('empathy_engine.penalties.mild') ?? 10);
|
|
406
514
|
}
|
|
515
|
+
|
|
407
516
|
/**
|
|
408
517
|
* EmpathyObserver workflow specification.
|
|
409
518
|
* This spec drives EmpathyObserverWorkflowManager for the empathy observer workflow.
|
|
410
519
|
*/
|
|
411
|
-
export const empathyObserverWorkflowSpec = {
|
|
520
|
+
export const empathyObserverWorkflowSpec: SubagentWorkflowSpec<EmpathyResult> = {
|
|
412
521
|
workflowType: 'empathy-observer',
|
|
413
522
|
transport: 'runtime_direct',
|
|
414
523
|
timeoutMs: 30_000,
|
|
415
524
|
ttlMs: 300_000,
|
|
416
525
|
shouldDeleteSessionAfterFinalize: true,
|
|
417
|
-
|
|
526
|
+
|
|
527
|
+
buildPrompt(taskInput: unknown, _metadata: WorkflowMetadata): string {
|
|
418
528
|
const userMessage = String(taskInput).trim();
|
|
419
529
|
return [
|
|
420
530
|
'You are an empathy observer.',
|
|
@@ -423,11 +533,12 @@ export const empathyObserverWorkflowSpec = {
|
|
|
423
533
|
`User message: ${JSON.stringify(userMessage)}`,
|
|
424
534
|
].join('\n');
|
|
425
535
|
},
|
|
426
|
-
|
|
536
|
+
|
|
537
|
+
async parseResult(ctx: WorkflowResultContext): Promise<EmpathyResult | null> {
|
|
427
538
|
const rawText = extractAssistantTextForSpec(ctx.messages, ctx.assistantTexts);
|
|
428
539
|
const payload = parseEmpathyPayloadForSpec(rawText);
|
|
429
|
-
if (!payload)
|
|
430
|
-
|
|
540
|
+
if (!payload) return null;
|
|
541
|
+
|
|
431
542
|
return {
|
|
432
543
|
damageDetected: payload.damageDetected ?? false,
|
|
433
544
|
severity: normalizeSeverityForSpec(payload.severity),
|
|
@@ -436,13 +547,22 @@ export const empathyObserverWorkflowSpec = {
|
|
|
436
547
|
painScore: 0,
|
|
437
548
|
};
|
|
438
549
|
},
|
|
439
|
-
|
|
550
|
+
|
|
551
|
+
async persistResult(ctx: WorkflowPersistContext<EmpathyResult>): Promise<void> {
|
|
440
552
|
const { result, metadata, workspaceDir } = ctx;
|
|
441
|
-
if (!result.damageDetected)
|
|
442
|
-
|
|
553
|
+
if (!result.damageDetected) return;
|
|
554
|
+
|
|
443
555
|
const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
|
|
444
556
|
const painScore = scoreFromSeverityForSpec(result.severity, wctx);
|
|
445
|
-
|
|
557
|
+
|
|
558
|
+
trackFriction(
|
|
559
|
+
metadata.parentSessionId,
|
|
560
|
+
painScore,
|
|
561
|
+
`observer_empathy_${result.severity}`,
|
|
562
|
+
workspaceDir,
|
|
563
|
+
{ source: 'user_empathy' }
|
|
564
|
+
);
|
|
565
|
+
|
|
446
566
|
const eventId = `emp_obs_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
447
567
|
wctx.eventLog.recordPainSignal(metadata.parentSessionId, {
|
|
448
568
|
score: painScore,
|
|
@@ -454,11 +574,12 @@ export const empathyObserverWorkflowSpec = {
|
|
|
454
574
|
confidence: result.confidence,
|
|
455
575
|
detection_mode: 'structured',
|
|
456
576
|
deduped: false,
|
|
457
|
-
trigger_text_excerpt: '',
|
|
577
|
+
trigger_text_excerpt: String(metadata.taskInput ?? '').substring(0, 120),
|
|
458
578
|
raw_score: painScore,
|
|
459
579
|
calibrated_score: painScore,
|
|
460
580
|
eventId,
|
|
461
581
|
});
|
|
582
|
+
|
|
462
583
|
try {
|
|
463
584
|
wctx.trajectory?.recordPainEvent?.({
|
|
464
585
|
sessionId: metadata.parentSessionId,
|
|
@@ -468,13 +589,15 @@ export const empathyObserverWorkflowSpec = {
|
|
|
468
589
|
severity: result.severity,
|
|
469
590
|
origin: 'system_infer',
|
|
470
591
|
confidence: result.confidence,
|
|
592
|
+
// Use runtime check instead of type assertion
|
|
593
|
+
text: typeof metadata.taskInput === 'string' ? metadata.taskInput : undefined,
|
|
471
594
|
});
|
|
472
|
-
}
|
|
473
|
-
catch (error) {
|
|
595
|
+
} catch (error) {
|
|
474
596
|
console.warn(`[PD:EmpathyObserverWorkflow] Failed to persist trajectory: ${String(error)}`);
|
|
475
597
|
}
|
|
476
598
|
},
|
|
477
|
-
|
|
599
|
+
|
|
600
|
+
shouldFinalizeOnWaitStatus(status: 'ok' | 'error' | 'timeout'): boolean {
|
|
478
601
|
return status === 'ok';
|
|
479
602
|
},
|
|
480
603
|
};
|