openclaw-hybrid-memory 2026.5.310 → 2026.6.10
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/api/plugin-runtime.ts +2 -0
- package/backends/facts-db/contradictions.ts +1 -1
- package/cli/cmd-extract-directives.ts +225 -11
- package/cli/cmd-extract-proposals.ts +5 -6
- package/cli/cmd-extract-reinforcement.ts +71 -0
- package/cli/cmd-feedback.ts +15 -9
- package/cli/commands/manage/register-reflection-pipeline.ts +247 -13
- package/cli/commands/manage/register-storage-maintenance.ts +224 -15
- package/cli/commands/manage/storage-stats-helpers.ts +13 -2
- package/cli/context.ts +9 -19
- package/cli/distill.ts +31 -1
- package/cli/register.ts +28 -38
- package/dist/api/plugin-runtime.js.map +1 -1
- package/dist/backends/agent-health-store.js.map +1 -1
- package/dist/backends/apitap-store.js.map +1 -1
- package/dist/backends/audit-store.js.map +1 -1
- package/dist/backends/base-sqlite-store.js.map +1 -1
- package/dist/backends/cost-tracker.js.map +1 -1
- package/dist/backends/credentials-db.js +2 -3
- package/dist/backends/credentials-db.js.map +1 -1
- package/dist/backends/crystallization-store.js.map +1 -1
- package/dist/backends/edict-store.js.map +1 -1
- package/dist/backends/event-bus.js.map +1 -1
- package/dist/backends/event-log.js.map +1 -1
- package/dist/backends/facts-db/cache-manager.js.map +1 -1
- package/dist/backends/facts-db/clusters.js.map +1 -1
- package/dist/backends/facts-db/contradictions.js +1 -1
- package/dist/backends/facts-db/contradictions.js.map +1 -1
- package/dist/backends/facts-db/crud.js.map +1 -1
- package/dist/backends/facts-db/db-connection.js.map +1 -1
- package/dist/backends/facts-db/entity-autolink.js.map +1 -1
- package/dist/backends/facts-db/entity-layer.js.map +1 -1
- package/dist/backends/facts-db/episodes.js.map +1 -1
- package/dist/backends/facts-db/fact-queries.js.map +1 -1
- package/dist/backends/facts-db/fact-read-queries.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer1.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer2.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer3.js.map +1 -1
- package/dist/backends/facts-db/fts-text.js.map +1 -1
- package/dist/backends/facts-db/generated-skills/policy.js.map +1 -1
- package/dist/backends/facts-db/generated-skills.js.map +1 -1
- package/dist/backends/facts-db/housekeeping.js.map +1 -1
- package/dist/backends/facts-db/links.js.map +1 -1
- package/dist/backends/facts-db/maintenance.js.map +1 -1
- package/dist/backends/facts-db/procedures/crud.js.map +1 -1
- package/dist/backends/facts-db/procedures/internal.js.map +1 -1
- package/dist/backends/facts-db/procedures/promotion.js.map +1 -1
- package/dist/backends/facts-db/procedures/search.js.map +1 -1
- package/dist/backends/facts-db/procedures/stats.js.map +1 -1
- package/dist/backends/facts-db/reinforcement.js.map +1 -1
- package/dist/backends/facts-db/row-mapper.js.map +1 -1
- package/dist/backends/facts-db/scan-cursors.js.map +1 -1
- package/dist/backends/facts-db/schema-bootstrap.js.map +1 -1
- package/dist/backends/facts-db/scope-sql.js.map +1 -1
- package/dist/backends/facts-db/search.js.map +1 -1
- package/dist/backends/facts-db/stats.js.map +1 -1
- package/dist/backends/facts-db/types.js.map +1 -1
- package/dist/backends/facts-db/variants.js.map +1 -1
- package/dist/backends/identity-reflection-store.js.map +1 -1
- package/dist/backends/issue-store.js.map +1 -1
- package/dist/backends/learnings-db.js.map +1 -1
- package/dist/backends/migrations/facts-migrations.js.map +1 -1
- package/dist/backends/migrations/procedures.js.map +1 -1
- package/dist/backends/narratives-db.js.map +1 -1
- package/dist/backends/persona-state-store.js.map +1 -1
- package/dist/backends/proposals-db.js.map +1 -1
- package/dist/backends/scope-filter-sql.js.map +1 -1
- package/dist/backends/sqlite-schema-meta.js.map +1 -1
- package/dist/backends/tool-proposal-store.js.map +1 -1
- package/dist/backends/vector-db/constants.js.map +1 -1
- package/dist/backends/vector-db/path-utils.js.map +1 -1
- package/dist/backends/vector-db/runtime-locks.js.map +1 -1
- package/dist/backends/vector-db/vector-db-class.js.map +1 -1
- package/dist/backends/wal.js.map +1 -1
- package/dist/backends/workflow-store.js.map +1 -1
- package/dist/benchmark/shadow-eval.js.map +1 -1
- package/dist/cli/active-tasks.js.map +1 -1
- package/dist/cli/backup.js.map +1 -1
- package/dist/cli/benchmark.js.map +1 -1
- package/dist/cli/cmd-backfill.js.map +1 -1
- package/dist/cli/cmd-config.js.map +1 -1
- package/dist/cli/cmd-credentials.js.map +1 -1
- package/dist/cli/cmd-demo.js.map +1 -1
- package/dist/cli/cmd-distill.js.map +1 -1
- package/dist/cli/cmd-doctor.js.map +1 -1
- package/dist/cli/cmd-examples.js.map +1 -1
- package/dist/cli/cmd-extract-daily.js.map +1 -1
- package/dist/cli/cmd-extract-directives.js +141 -10
- package/dist/cli/cmd-extract-directives.js.map +1 -1
- package/dist/cli/cmd-extract-procedures.js.map +1 -1
- package/dist/cli/cmd-extract-proposals.js +3 -2
- package/dist/cli/cmd-extract-proposals.js.map +1 -1
- package/dist/cli/cmd-extract-reinforcement.js +39 -0
- package/dist/cli/cmd-extract-reinforcement.js.map +1 -1
- package/dist/cli/cmd-extract-sessions.js.map +1 -1
- package/dist/cli/cmd-feedback.js +9 -4
- package/dist/cli/cmd-feedback.js.map +1 -1
- package/dist/cli/cmd-health.js.map +1 -1
- package/dist/cli/cmd-providers.js.map +1 -1
- package/dist/cli/cmd-selfcorrection.js.map +1 -1
- package/dist/cli/cmd-setup.js.map +1 -1
- package/dist/cli/cmd-status.js.map +1 -1
- package/dist/cli/cmd-store.js.map +1 -1
- package/dist/cli/cmd-user-friendly.js.map +1 -1
- package/dist/cli/cmd-verify.js.map +1 -1
- package/dist/cli/commands/manage/bindings.js.map +1 -1
- package/dist/cli/commands/manage/dream-cycle-followup.js.map +1 -1
- package/dist/cli/commands/manage/maintenance-heartbeat.js.map +1 -1
- package/dist/cli/commands/manage/register-agents-audit-runall.js.map +1 -1
- package/dist/cli/commands/manage/register-analyze-maintenance-logs.js.map +1 -1
- package/dist/cli/commands/manage/register-budget-proposals.js.map +1 -1
- package/dist/cli/commands/manage/register-config-cli.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections-and-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections.js.map +1 -1
- package/dist/cli/commands/manage/register-council.js.map +1 -1
- package/dist/cli/commands/manage/register-credentials-scope.js.map +1 -1
- package/dist/cli/commands/manage/register-digest.js.map +1 -1
- package/dist/cli/commands/manage/register-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-procedure-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-reconcile-cron-ledgers.js.map +1 -1
- package/dist/cli/commands/manage/register-reflection-pipeline.js +144 -7
- package/dist/cli/commands/manage/register-reflection-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-self-correction-feedback.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-and-stats.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-entities-decay.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-graph-audit.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-maintenance.js +152 -9
- package/dist/cli/commands/manage/register-storage-maintenance.js.map +1 -1
- package/dist/cli/commands/manage/register-validate-cron-exit.js.map +1 -1
- package/dist/cli/commands/manage/storage-stats-helpers.js +10 -3
- package/dist/cli/commands/manage/storage-stats-helpers.js.map +1 -1
- package/dist/cli/commands/register-manage-commands.js.map +1 -1
- package/dist/cli/config-feature-summaries.js.map +1 -1
- package/dist/cli/config-output-sink.js.map +1 -1
- package/dist/cli/distill-session-jsonl.js.map +1 -1
- package/dist/cli/distill.js +10 -1
- package/dist/cli/distill.js.map +1 -1
- package/dist/cli/global-verbose.js.map +1 -1
- package/dist/cli/goals.js.map +1 -1
- package/dist/cli/hybrid-mem-commander-utils.js.map +1 -1
- package/dist/cli/install/config-merge.js.map +1 -1
- package/dist/cli/install/cron-jobs.js.map +1 -1
- package/dist/cli/install/embedding-detect.js.map +1 -1
- package/dist/cli/install/run-install.js.map +1 -1
- package/dist/cli/install/workspace.js.map +1 -1
- package/dist/cli/proposals.js.map +1 -1
- package/dist/cli/register.js.map +1 -1
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/task-queue-status.js.map +1 -1
- package/dist/cli/verified.js.map +1 -1
- package/dist/cli/verify/fact-count.js.map +1 -1
- package/dist/cli/verify/openclaw-config.js.map +1 -1
- package/dist/cli/verify/plugin-config-credentials.js.map +1 -1
- package/dist/cli/verify/sections/config-cron.js.map +1 -1
- package/dist/cli/verify/sections/embeddings.js.map +1 -1
- package/dist/cli/verify/sections/infrastructure.js.map +1 -1
- package/dist/cli/verify/sections/llm-models.js.map +1 -1
- package/dist/cli/verify/sections/reconcile.js.map +1 -1
- package/dist/cli/verify/verify-run-state.js.map +1 -1
- package/dist/cli/verify-llm-azure-auth.js.map +1 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/config/hybrid-schema.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/maintenance-fallback-policy.js.map +1 -1
- package/dist/config/parsers/capture.js.map +1 -1
- package/dist/config/parsers/core.js.map +1 -1
- package/dist/config/parsers/features.js.map +1 -1
- package/dist/config/parsers/index.js.map +1 -1
- package/dist/config/parsers/maintenance.js.map +1 -1
- package/dist/config/parsers/retrieval.js.map +1 -1
- package/dist/config/parsers/sensors.js.map +1 -1
- package/dist/config/skill-sections.js.map +1 -1
- package/dist/config/skill-size-limits.js.map +1 -1
- package/dist/config/types/agents.js.map +1 -1
- package/dist/config/types/bootstrap.js.map +1 -1
- package/dist/config/types/core.js.map +1 -1
- package/dist/config/types/index.js.map +1 -1
- package/dist/config/utils.js.map +1 -1
- package/dist/index-help.js.map +1 -1
- package/dist/index-testing-exports.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/hook-resolution-api.js.map +1 -1
- package/dist/lifecycle/hooks.js +0 -1
- package/dist/lifecycle/hooks.js.map +1 -1
- package/dist/lifecycle/resolve-agent-id.js.map +1 -1
- package/dist/lifecycle/session-state.js.map +1 -1
- package/dist/lifecycle/stage-active-task.js.map +1 -1
- package/dist/lifecycle/stage-auth-failure.js.map +1 -1
- package/dist/lifecycle/stage-capture/run-capture.js.map +1 -1
- package/dist/lifecycle/stage-capture.js.map +1 -1
- package/dist/lifecycle/stage-cleanup.js.map +1 -1
- package/dist/lifecycle/stage-credential-hint.js.map +1 -1
- package/dist/lifecycle/stage-frustration.js.map +1 -1
- package/dist/lifecycle/stage-goal-stewardship.js.map +1 -1
- package/dist/lifecycle/stage-goal-subagent.js.map +1 -1
- package/dist/lifecycle/stage-injection.js +1 -1
- package/dist/lifecycle/stage-injection.js.map +1 -1
- package/dist/lifecycle/stage-recall/run-recall.js.map +1 -1
- package/dist/lifecycle/stage-recall.js.map +1 -1
- package/dist/lifecycle/stage-setup.js.map +1 -1
- package/dist/routes/dashboard/collectors.js.map +1 -1
- package/dist/routes/dashboard/html.js.map +1 -1
- package/dist/routes/dashboard/server.js.map +1 -1
- package/dist/routes/dashboard-graph.js.map +1 -1
- package/dist/routes/graphql-resolvers.js.map +1 -1
- package/dist/routes/graphql-server.js.map +1 -1
- package/dist/services/active-task-checkpoint.js.map +1 -1
- package/dist/services/active-task-injection.js.map +1 -1
- package/dist/services/active-task.js.map +1 -1
- package/dist/services/adaptive-catch-up-pacing.js +25 -0
- package/dist/services/adaptive-catch-up-pacing.js.map +1 -0
- package/dist/services/adaptive-maintenance-llm.js.map +1 -1
- package/dist/services/adaptive-model-limits.js.map +1 -1
- package/dist/services/ambient-retrieval.js.map +1 -1
- package/dist/services/apitap-service.js.map +1 -1
- package/dist/services/audit-health-exit-info.js.map +1 -1
- package/dist/services/audit-health-json.js.map +1 -1
- package/dist/services/auth-failure-detect.js.map +1 -1
- package/dist/services/auto-capture.js.map +1 -1
- package/dist/services/auto-classifier.js.map +1 -1
- package/dist/services/auto-skills-audit.js.map +1 -1
- package/dist/services/bootstrap-optional.js.map +1 -1
- package/dist/services/bootstrap-priority.js.map +1 -1
- package/dist/services/bootstrap.js.map +1 -1
- package/dist/services/capture-provenance.js.map +1 -1
- package/dist/services/capture-utils.js.map +1 -1
- package/dist/services/chat.js +22 -3
- package/dist/services/chat.js.map +1 -1
- package/dist/services/classification-scope.js.map +1 -1
- package/dist/services/classification.js.map +1 -1
- package/dist/services/cli-sql-dump.js.map +1 -1
- package/dist/services/consolidation.js.map +1 -1
- package/dist/services/context-audit.js +1 -1
- package/dist/services/context-audit.js.map +1 -1
- package/dist/services/context-budget.js.map +1 -1
- package/dist/services/context-engine.js.map +1 -1
- package/dist/services/contextual-variants.js.map +1 -1
- package/dist/services/continuous-verifier.js.map +1 -1
- package/dist/services/contradiction-adjudicator.js.map +1 -1
- package/dist/services/cost-context.js.map +1 -1
- package/dist/services/cost-feature-labels.js.map +1 -1
- package/dist/services/credential-migration.js.map +1 -1
- package/dist/services/credential-scanner.js.map +1 -1
- package/dist/services/credential-validation.js.map +1 -1
- package/dist/services/cron-exit-validator.js.map +1 -1
- package/dist/services/cron-guard.js.map +1 -1
- package/dist/services/cron-job-bash-harness.js +52 -5
- package/dist/services/cron-job-bash-harness.js.map +1 -1
- package/dist/services/cron-maintenance-reconciler.js +1 -3
- package/dist/services/cron-maintenance-reconciler.js.map +1 -1
- package/dist/services/cross-agent-learning.js.map +1 -1
- package/dist/services/crystallization-proposer.js.map +1 -1
- package/dist/services/dedupe-policy.js.map +1 -1
- package/dist/services/deprecated-cron-commands.js.map +1 -1
- package/dist/services/directive-extract.js.map +1 -1
- package/dist/services/document-chunker.js.map +1 -1
- package/dist/services/document-grader.js.map +1 -1
- package/dist/services/dream-cycle.js.map +1 -1
- package/dist/services/embedding-migration.js.map +1 -1
- package/dist/services/embedding-registry.js.map +1 -1
- package/dist/services/embeddings/chain-provider.js.map +1 -1
- package/dist/services/embeddings/factory.js.map +1 -1
- package/dist/services/embeddings/fallback-provider.js.map +1 -1
- package/dist/services/embeddings/ollama-provider.js.map +1 -1
- package/dist/services/embeddings/onnx-provider.js.map +1 -1
- package/dist/services/embeddings/openai-provider.js.map +1 -1
- package/dist/services/embeddings/shared.js +3 -3
- package/dist/services/embeddings/shared.js.map +1 -1
- package/dist/services/embeddings/types.js.map +1 -1
- package/dist/services/entity-enrichment-adaptive.js +128 -0
- package/dist/services/entity-enrichment-adaptive.js.map +1 -0
- package/dist/services/entity-enrichment-cli.js +389 -42
- package/dist/services/entity-enrichment-cli.js.map +1 -1
- package/dist/services/entity-enrichment.js +31 -5
- package/dist/services/entity-enrichment.js.map +1 -1
- package/dist/services/error-reporter/noisy-errors.js.map +1 -1
- package/dist/services/error-reporter/sanitize.js.map +1 -1
- package/dist/services/error-reporter.js.map +1 -1
- package/dist/services/event-hub-repair.js.map +1 -1
- package/dist/services/export-memory.js.map +1 -1
- package/dist/services/fact-extraction.js.map +1 -1
- package/dist/services/feedback-effectiveness.js.map +1 -1
- package/dist/services/find-duplicates.js.map +1 -1
- package/dist/services/frustration-detector.js.map +1 -1
- package/dist/services/fts-search.js.map +1 -1
- package/dist/services/gap-detector.js.map +1 -1
- package/dist/services/generated-skill-lifecycle.js.map +1 -1
- package/dist/services/generated-skill-validation.js.map +1 -1
- package/dist/services/goal-active-task-mirror.js.map +1 -1
- package/dist/services/goal-circuit-breaker.js.map +1 -1
- package/dist/services/goal-health.js.map +1 -1
- package/dist/services/goal-registry.js.map +1 -1
- package/dist/services/goal-stewardship-heartbeat.js.map +1 -1
- package/dist/services/goal-stewardship-llm-triage.js.map +1 -1
- package/dist/services/goal-stewardship-verify-cron.js.map +1 -1
- package/dist/services/goal-stewardship.js.map +1 -1
- package/dist/services/goal-subagent.js.map +1 -1
- package/dist/services/graph-retrieval.js.map +1 -1
- package/dist/services/humanizer-score.js.map +1 -1
- package/dist/services/hybrid-mem-cron-default-job-steps.js.map +1 -1
- package/dist/services/hyde-helper.js.map +1 -1
- package/dist/services/identity-reflection.js.map +1 -1
- package/dist/services/implicit-feedback-extract.js.map +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/ingest-utils.js.map +1 -1
- package/dist/services/intent-template.js.map +1 -1
- package/dist/services/json-array-parser.js.map +1 -1
- package/dist/services/knowledge-gaps.js.map +1 -1
- package/dist/services/language-keywords-build.js.map +1 -1
- package/dist/services/lifecycle/github-adapter.js.map +1 -1
- package/dist/services/llm-rate-limit-headers.js +1 -2
- package/dist/services/llm-rate-limit-headers.js.map +1 -1
- package/dist/services/maintenance-auto-fix.js.map +1 -1
- package/dist/services/maintenance-log-analyzer.js +7 -1
- package/dist/services/maintenance-log-analyzer.js.map +1 -1
- package/dist/services/maintenance-timestamp.js.map +1 -1
- package/dist/services/memory-diagnostics.js.map +1 -1
- package/dist/services/memory-index.js.map +1 -1
- package/dist/services/merge-results.js.map +1 -1
- package/dist/services/model-capabilities.js.map +1 -1
- package/dist/services/model-pricing.js.map +1 -1
- package/dist/services/narrative-recall.js.map +1 -1
- package/dist/services/openclaw-session-artifact.js.map +1 -1
- package/dist/services/passive-observer.js.map +1 -1
- package/dist/services/pattern-detector-hash.js.map +1 -1
- package/dist/services/pattern-detector.js.map +1 -1
- package/dist/services/pending-autopilot/foundation.js.map +1 -1
- package/dist/services/pending-autopilot/redaction.js.map +1 -1
- package/dist/services/pending-autopilot/store.js.map +1 -1
- package/dist/services/pending-autopilot/types.js.map +1 -1
- package/dist/services/pending-digest-autopilot-cron.js.map +1 -1
- package/dist/services/pending-digest-autopilot.js.map +1 -1
- package/dist/services/pending-review-digest.js.map +1 -1
- package/dist/services/persona-proposal-triage.js.map +1 -1
- package/dist/services/persona-state-promotion.js.map +1 -1
- package/dist/services/post-compaction-recall.js.map +1 -1
- package/dist/services/pre-consolidation-flush.js.map +1 -1
- package/dist/services/pre-finalization-guard.js.map +1 -1
- package/dist/services/procedure-cluster.js.map +1 -1
- package/dist/services/procedure-extractor.js.map +1 -1
- package/dist/services/procedure-promotion/duplicate-skill-cache.js.map +1 -1
- package/dist/services/procedure-promotion-policy.js.map +1 -1
- package/dist/services/procedure-selection-metrics.js.map +1 -1
- package/dist/services/procedure-skill-eval.js.map +1 -1
- package/dist/services/procedure-skill-generator.js.map +1 -1
- package/dist/services/procedure-skill-recipe.js.map +1 -1
- package/dist/services/procedure-skill-shrink.js.map +1 -1
- package/dist/services/procedure-skill-workflow.js.map +1 -1
- package/dist/services/provenance.js.map +1 -1
- package/dist/services/public-export-bundle.js.map +1 -1
- package/dist/services/python-bridge.js.map +1 -1
- package/dist/services/query-expander.js.map +1 -1
- package/dist/services/query-validator.js.map +1 -1
- package/dist/services/recall-pipeline.js.map +1 -1
- package/dist/services/recall-timing.js.map +1 -1
- package/dist/services/recent-http-attempts.js.map +1 -1
- package/dist/services/reflection/shared.js.map +1 -1
- package/dist/services/reflection.js.map +1 -1
- package/dist/services/reinforcement-extract.js.map +1 -1
- package/dist/services/reranker.js.map +1 -1
- package/dist/services/responses-adapter.js.map +1 -1
- package/dist/services/retrieval-aliases.js.map +1 -1
- package/dist/services/retrieval-mode-policy.js.map +1 -1
- package/dist/services/retrieval-orchestrator/packing.js.map +1 -1
- package/dist/services/retrieval-orchestrator.d.ts +2 -3
- package/dist/services/retrieval-orchestrator.js.map +1 -1
- package/dist/services/rrf-fusion.js.map +1 -1
- package/dist/services/self-correction-extract.js.map +1 -1
- package/dist/services/session-observability.js.map +1 -1
- package/dist/services/session-pre-filter.js.map +1 -1
- package/dist/services/shortest-path.js.map +1 -1
- package/dist/services/skill-allowed-tools.js.map +1 -1
- package/dist/services/skill-creator-validator.js.map +1 -1
- package/dist/services/skill-crystallizer-helpers.js.map +1 -1
- package/dist/services/skill-crystallizer.js.map +1 -1
- package/dist/services/skill-description-builder.js.map +1 -1
- package/dist/services/skill-eval-synthesizer.js.map +1 -1
- package/dist/services/skill-examples-builder.js.map +1 -1
- package/dist/services/skill-frontmatter.js.map +1 -1
- package/dist/services/skill-name-validator.js.map +1 -1
- package/dist/services/skill-prompt-injection.js.map +1 -1
- package/dist/services/skill-reference-sidecar.js.map +1 -1
- package/dist/services/skill-script-bundler.js.map +1 -1
- package/dist/services/skill-validator.js.map +1 -1
- package/dist/services/startup-memory-attribution.js.map +1 -1
- package/dist/services/task-hygiene.js.map +1 -1
- package/dist/services/task-ledger/canonical.js.map +1 -1
- package/dist/services/task-ledger-facts.js.map +1 -1
- package/dist/services/task-queue-leases.js.map +1 -1
- package/dist/services/task-queue-watchdog.js.map +1 -1
- package/dist/services/tool-effectiveness.js.map +1 -1
- package/dist/services/tool-proposer.js.map +1 -1
- package/dist/services/tools-md-section.js.map +1 -1
- package/dist/services/topic-clusters.js.map +1 -1
- package/dist/services/trajectory-tracker.js.map +1 -1
- package/dist/services/vector-backend-observability.js.map +1 -1
- package/dist/services/vector-lifecycle-audit.js.map +1 -1
- package/dist/services/vector-maintenance.js.map +1 -1
- package/dist/services/vector-search.js.map +1 -1
- package/dist/services/verification-store.js.map +1 -1
- package/dist/services/verified-fact-triage.js.map +1 -1
- package/dist/services/wal-helpers.js.map +1 -1
- package/dist/services/workflow-tracker.js.map +1 -1
- package/dist/setup/bootstrap-databases.js.map +1 -1
- package/dist/setup/cli-context/cli-services.js.map +1 -1
- package/dist/setup/cli-context/help-text.js.map +1 -1
- package/dist/setup/cli-context/metadata.js.map +1 -1
- package/dist/setup/cli-context/register-cli-with-help.js.map +1 -1
- package/dist/setup/cli-context/register-full.js.map +1 -1
- package/dist/setup/cli-context/register-help.js.map +1 -1
- package/dist/setup/cost-instrumentation.js.map +1 -1
- package/dist/setup/hybrid-memory-generation-state.js.map +1 -1
- package/dist/setup/hybrid-memory-reload-coordinator.js +13 -13
- package/dist/setup/hybrid-memory-reload-coordinator.js.map +1 -1
- package/dist/setup/plugin-service.js.map +1 -1
- package/dist/setup/provider-router.js.map +1 -1
- package/dist/setup/register-context-engine.js.map +1 -1
- package/dist/setup/register-hooks.js.map +1 -1
- package/dist/setup/register-plugin.js +25 -21
- package/dist/setup/register-plugin.js.map +1 -1
- package/dist/setup/register-tools.js.map +1 -1
- package/dist/setup/reregister-policy.js +2 -2
- package/dist/setup/reregister-policy.js.map +1 -1
- package/dist/setup/tool-installers.js.map +1 -1
- package/dist/setup/workspace-bootstrap.js.map +1 -1
- package/dist/src/worker/narratives.js.map +1 -1
- package/dist/tools/apitap-tools.js.map +1 -1
- package/dist/tools/credential-tools.js.map +1 -1
- package/dist/tools/crystallization-tools.js.map +1 -1
- package/dist/tools/dashboard-routes.js.map +1 -1
- package/dist/tools/document-tools.js.map +1 -1
- package/dist/tools/goal-tools.js.map +1 -1
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/issue-tools.js.map +1 -1
- package/dist/tools/memory/build-runtime.js.map +1 -1
- package/dist/tools/memory/helpers.js.map +1 -1
- package/dist/tools/memory/register-checkpoint-tools.js.map +1 -1
- package/dist/tools/memory/register-directory-tools.js.map +1 -1
- package/dist/tools/memory/register-edict-tools.js.map +1 -1
- package/dist/tools/memory/register-episode-tools.js.map +1 -1
- package/dist/tools/memory/register-recall-tools.js.map +1 -1
- package/dist/tools/memory/register-store-tools.js.map +1 -1
- package/dist/tools/memory-tools.js.map +1 -1
- package/dist/tools/persona-tools.js.map +1 -1
- package/dist/tools/provenance-tools.js.map +1 -1
- package/dist/tools/public-api-routes.js.map +1 -1
- package/dist/tools/safe-register-http-route.js.map +1 -1
- package/dist/tools/self-extension-tools.js.map +1 -1
- package/dist/tools/task-hygiene-tools.js.map +1 -1
- package/dist/tools/utility-tools.js.map +1 -1
- package/dist/tools/verification-tools.js.map +1 -1
- package/dist/tools/workflow-tools.js.map +1 -1
- package/dist/types/issue-types.js.map +1 -1
- package/dist/types/learnings-types.js.map +1 -1
- package/dist/types/memory.js.map +1 -1
- package/dist/utils/apim-gateway-fetch.js.map +1 -1
- package/dist/utils/atomic-write.js.map +1 -1
- package/dist/utils/auth-failover.js.map +1 -1
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/compaction-model-watchdog.js.map +1 -1
- package/dist/utils/consolidation-controls.js.map +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/date-detector.js.map +1 -1
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/decay.js.map +1 -1
- package/dist/utils/duration.js.map +1 -1
- package/dist/utils/embed-call.js.map +1 -1
- package/dist/utils/entity-lookup-resolve.js.map +1 -1
- package/dist/utils/entity-mention-quality.js.map +1 -1
- package/dist/utils/entity-stopwords.js.map +1 -1
- package/dist/utils/env-manager.js.map +1 -1
- package/dist/utils/error-tracking.js.map +1 -1
- package/dist/utils/event-loop-yield.js.map +1 -1
- package/dist/utils/extract-last-user-message.js.map +1 -1
- package/dist/utils/extraction-from-template.js.map +1 -1
- package/dist/utils/fact-embeddings.js.map +1 -1
- package/dist/utils/file-snapshot.js.map +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/gh-repo-arg.js.map +1 -1
- package/dist/utils/hybrid-mem-json-cli.js.map +1 -1
- package/dist/utils/language-keywords.js.map +1 -1
- package/dist/utils/lifecycle-generation.js.map +1 -1
- package/dist/utils/llm-json-array.js.map +1 -1
- package/dist/utils/llm-selection.js.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model-provider-family.js.map +1 -1
- package/dist/utils/model-tier.js.map +1 -1
- package/dist/utils/openclaw-agent-defaults.js.map +1 -1
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/plugin-root.js.map +1 -1
- package/dist/utils/plugin-update-check.js.map +1 -1
- package/dist/utils/procedure-risk.js.map +1 -1
- package/dist/utils/progress-indicators.js.map +1 -1
- package/dist/utils/prompt-loader.js.map +1 -1
- package/dist/utils/provenance.js.map +1 -1
- package/dist/utils/provider-detection.js.map +1 -1
- package/dist/utils/registration-superseded.js.map +1 -1
- package/dist/utils/salience.js.map +1 -1
- package/dist/utils/sanitize-messages.js.map +1 -1
- package/dist/utils/scope-filter.js.map +1 -1
- package/dist/utils/skill-discovery.js.map +1 -1
- package/dist/utils/sqlite-file-perms.js.map +1 -1
- package/dist/utils/sqlite-outcome-compat.js.map +1 -1
- package/dist/utils/sqlite-transaction.js.map +1 -1
- package/dist/utils/stable-stringify.js.map +1 -1
- package/dist/utils/subagent-ended-utils.js.map +1 -1
- package/dist/utils/tags.js.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/timeout.js.map +1 -1
- package/dist/utils/typebox.js.map +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/wal-replay.js.map +1 -1
- package/dist/versionInfo.js.map +1 -1
- package/index.ts +2 -2
- package/lifecycle/hooks.ts +0 -1
- package/npm-shrinkwrap.json +487 -186
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/services/adaptive-catch-up-pacing.ts +28 -0
- package/services/chat.ts +34 -1
- package/services/cron-job-bash-harness.ts +52 -5
- package/services/embeddings/shared.ts +5 -2
- package/services/entity-enrichment-adaptive.ts +245 -0
- package/services/entity-enrichment-cli.ts +553 -47
- package/services/entity-enrichment.ts +43 -2
- package/services/llm-rate-limit-headers.ts +1 -4
- package/services/maintenance-log-analyzer.ts +13 -9
- package/services/reinforcement-extract.ts +19 -0
- package/setup/hybrid-memory-reload-coordinator.ts +26 -0
- package/setup/register-plugin.ts +62 -32
- package/setup/reregister-policy.ts +10 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","names":[],"sources":["../../lifecycle/hooks.ts"],"sourcesContent":["import { getEnv } from \"../utils/env-manager.js\";\n/**\n * Lifecycle Hooks (Phase 2.3: staged pipeline).\n *\n * Dispatcher: registers before_agent_start, agent_end, and frustration handlers (subagent hooks: stage-cleanup).\n * All stage logic lives in stage-*.ts and session-state.ts; this file stays <200 lines.\n */\n\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../config/index.js\";\nimport \"../config.js\";\nimport { isAbortOrTransientLlmError } from \"../services/chat.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildDailyNarrative } from \"../src/worker/narratives.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { createSessionState } from \"./session-state.js\";\nimport { registerActiveTaskInjection } from \"./stage-active-task.js\";\nimport { registerAuthFailureRecall } from \"./stage-auth-failure.js\";\nimport { runCaptureStage } from \"./stage-capture.js\";\nimport { createStaleSweepTimer, getDispose, registerCleanupHandlers } from \"./stage-cleanup.js\";\nimport { registerCredentialHint } from \"./stage-credential-hint.js\";\nimport { registerFrustrationHandlers } from \"./stage-frustration.js\";\nimport { registerGoalStewardshipInjection, resolvedGoalsDirForLifecycle } from \"./stage-goal-stewardship.js\";\nimport { registerGoalSubagentHandlers } from \"./stage-goal-subagent.js\";\nimport { runInjectionStage } from \"./stage-injection.js\";\nimport { runRecallStage } from \"./stage-recall.js\";\nimport { runSetupStage } from \"./stage-setup.js\";\nimport { formatPreFinalizationGuardMessage, evaluatePreFinalizationGuard } from \"../services/pre-finalization-guard.js\";\nimport { TASK_LEDGER_CATEGORY } from \"../services/task-ledger-facts.js\";\nimport { isRecallContextSuperseded, suppressStaleLifecycleDbError } from \"../utils/registration-superseded.js\";\nimport type { LifecycleContext } from \"./types.js\";\nimport { isStaleLifecycleGeneration } from \"../utils/lifecycle-generation.js\";\n\nexport type { LifecycleContext } from \"./types.js\";\n\nexport function createLifecycleHooks(ctx: LifecycleContext) {\n const sessionState = createSessionState();\n const staleSweepTimer = createStaleSweepTimer(sessionState);\n let firstRecallCheckpointCaptured = false;\n\n const workspaceRoot = getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n const resolvedActiveTaskPath = isAbsolute(ctx.cfg.activeTask.filePath)\n ? ctx.cfg.activeTask.filePath\n : join(workspaceRoot, ctx.cfg.activeTask.filePath);\n\n const onAgentStart = (api: ClawdbotPluginApi) => {\n // OpenClaw typed hooks: (event, PluginHookAgentContext). Second arg must be declared so\n // sessionKey/sessionId/agentId reach resolvers via withHookResolutionApi (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n await runSetupStage(event, rApi, ctx, sessionState);\n });\n\n if (ctx.cfg.autoRecall.enabled) {\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const shouldCaptureFirstRecall = !firstRecallCheckpointCaptured;\n const capturedFirstRecallBegin =\n shouldCaptureFirstRecall &&\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.begin\",\n onceKey: \"startup.first-recall.begin\",\n }) !== null;\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = true;\n }\n try {\n const recallStageResult = await runRecallStage(event, rApi, ctx, sessionState);\n if (isStaleLifecycleGeneration(ctx)) {\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = false;\n }\n return undefined;\n }\n if (!recallStageResult) {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: \"timeout\",\n },\n });\n }\n return undefined;\n }\n if (recallStageResult.kind === \"degraded\") {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return { prependContext: recallStageResult.prependContext };\n }\n if (recallStageResult.kind === \"empty\") {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return recallStageResult.prependContext ? { prependContext: recallStageResult.prependContext } : undefined;\n }\n const inj = await runInjectionStage(recallStageResult.result, rApi, ctx, event);\n if (isStaleLifecycleGeneration(ctx)) {\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = false;\n }\n return undefined;\n }\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return inj ?? undefined;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (\n isStaleLifecycleGeneration(ctx) &&\n /not open|connection is not open|database is not open/i.test(message)\n ) {\n api.logger.debug?.(\"memory-hybrid: recall skipped (stale lifecycle generation)\");\n return undefined;\n }\n if (isRecallContextSuperseded(ctx)) {\n api.logger.debug?.(\"memory-hybrid: recall skipped (registration superseded during reload)\");\n return undefined;\n }\n if (\n suppressStaleLifecycleDbError(\n ctx,\n err,\n api.logger,\n \"memory-hybrid: recall skipped (database closed during reload)\",\n )\n ) {\n return undefined;\n }\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.error\",\n onceKey: \"startup.first-recall.error\",\n tags: {\n error: err instanceof Error ? err.name : \"unknown\",\n },\n });\n }\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"recall\",\n subsystem: \"auto-recall\",\n });\n api.logger.warn(`memory-hybrid: recall failed: ${String(err)}`);\n }\n return undefined;\n });\n }\n\n registerActiveTaskInjection(api, ctx, resolvedActiveTaskPath, workspaceRoot);\n const resolvedGoalsDir = resolvedGoalsDirForLifecycle(ctx.cfg);\n registerGoalStewardshipInjection(\n api,\n ctx,\n resolvedGoalsDir,\n ctx.cfg.activeTask.enabled ? resolvedActiveTaskPath : undefined,\n );\n registerGoalSubagentHandlers(api, ctx, resolvedGoalsDir);\n registerCleanupHandlers(api, ctx, sessionState, resolvedActiveTaskPath, workspaceRoot);\n // Guard experimental/optional features at the registration point — avoids registering\n // event listeners whose bodies immediately return when disabled (#581).\n if (ctx.cfg.autoRecall.enabled && ctx.cfg.autoRecall.authFailure.enabled) {\n registerAuthFailureRecall(api, ctx, sessionState);\n }\n // Note: credential hints are gated on verbosity !== \"silent\" because their output\n // (a prepended hint block) is meaningless in silent mode. This is intentional:\n // the feature adds context only when the agent can surface it. If credential detection\n // without output injection is ever needed, split the guard accordingly.\n if (ctx.cfg.credentials.enabled && ctx.cfg.credentials.autoDetect && ctx.cfg.verbosity !== \"silent\") {\n registerCredentialHint(api, ctx);\n }\n };\n\n const onFrustrationDetect = (api: ClawdbotPluginApi) => {\n registerFrustrationHandlers(api, ctx, sessionState);\n };\n\n const onAgentEnd = (api: ClawdbotPluginApi) => {\n // Same typed-hook shape as before_agent_start (#1005).\n api.on(\"agent_end\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const ev = event as { messages?: unknown[]; success?: boolean };\n\n if (isStaleLifecycleGeneration(ctx)) return;\n\n // Issue #742: extract tool names from messages and record via WorkflowTracker\n // so crystallization can detect patterns from the traces table.\n if (ctx.workflowTracker && ctx.cfg.workflowTracking?.enabled) {\n try {\n const messages = ev?.messages ?? [];\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n\n // Extract goal from first user message (used as trace label)\n let goal = \"unknown\";\n for (const msg of messages) {\n if (msg && typeof msg === \"object\" && (msg as { role?: string }).role === \"user\") {\n const content = (msg as { content?: unknown }).content;\n if (typeof content === \"string\" && content.trim()) {\n goal = content.trim().slice(0, 200);\n break;\n }\n }\n }\n\n // Get session start time from sessionLastActivity (set during before_agent_start)\n const sessionStartTime = sessionState.sessionLastActivity.get(sessionId);\n\n // Push each tool call onto the tracker buffer with the actual session start time\n for (const msg of messages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n if (msgObj.role !== \"assistant\") continue;\n const toolCalls = msgObj.tool_calls;\n if (!Array.isArray(toolCalls)) continue;\n for (const tc of toolCalls) {\n if (!tc || typeof tc !== \"object\") continue;\n const fn = (tc as Record<string, unknown>).function as Record<string, unknown> | undefined;\n if (fn && typeof fn.name === \"string\") {\n ctx.workflowTracker?.push(sessionId, fn.name, sessionStartTime);\n }\n }\n }\n\n // Flush buffer to workflow-traces.db\n const outcome = ev?.success === true ? \"success\" : ev?.success === false ? \"failure\" : \"unknown\";\n const traceId = ctx.workflowTracker?.flush(sessionId, goal, outcome);\n if (traceId) {\n api.logger.debug?.(`memory-hybrid: workflow trace recorded id=${traceId} session=${sessionId}`);\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"workflow-tracking\",\n operation: \"agent-end-track-workflow\",\n sessionId: sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\",\n });\n api.logger.warn(`memory-hybrid: workflow tracking failed: ${String(err)}`);\n }\n }\n\n if (isStaleLifecycleGeneration(ctx)) {\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n sessionState.clearSessionState(sessionId);\n return;\n }\n await runCaptureStage(event, rApi, ctx, sessionState);\n if (isStaleLifecycleGeneration(ctx)) return;\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n if (isStaleLifecycleGeneration(ctx)) return;\n if (ctx.cfg.goalStewardship?.enabled) {\n try {\n const { listActiveGoals, resolveGoalsDir } = await import(\"../services/goal-stewardship.js\");\n const gDir = resolveGoalsDir(workspaceRoot, ctx.cfg.goalStewardship.goalsDir);\n const activeGoals = await listActiveGoals(gDir);\n if (activeGoals.length > 0) {\n api.logger.debug?.(\n `memory-hybrid: active goals at session end: ${activeGoals.map((g) => `${g.label}(${g.status})`).join(\", \")}`,\n );\n try {\n ctx.eventLog?.append({\n sessionId,\n timestamp: new Date().toISOString(),\n eventType: \"action_taken\",\n content: {\n kind: \"goal.session_summary\",\n activeGoals: activeGoals.map((g) => ({\n id: g.id,\n label: g.label,\n status: g.status,\n assessments: g.assessmentCount,\n })),\n },\n });\n } catch {\n /* non-fatal */\n }\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: goal session summary failed (non-fatal): ${String(err)}`);\n }\n }\n if (isStaleLifecycleGeneration(ctx)) return;\n\n try {\n await buildDailyNarrative({\n sessionId,\n eventLog: ctx.eventLog,\n workflowStore: ctx.workflowStore,\n narrativesDb: ctx.narrativesDb,\n openai: ctx.openai,\n model: getDefaultCronModel(getCronModelConfig(ctx.cfg), \"nano\"),\n logger: api.logger,\n fallbackModels: [],\n registrationGeneration: ctx.registrationGeneration,\n currentRegistrationGenerationRef: ctx.currentRegistrationGenerationRef,\n });\n } catch (err) {\n const transient = isAbortOrTransientLlmError(err);\n if (!transient) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"narratives\",\n operation: \"agent-end-build-narrative\",\n sessionId,\n });\n }\n const detail = err instanceof Error ? err.message : String(err);\n if (transient) {\n api.logger.info?.(`memory-hybrid: session narrative skipped (LLM unavailable or aborted): ${detail}`);\n } else {\n api.logger.warn(`memory-hybrid: session narrative build failed: ${String(err)}`);\n }\n }\n if (isStaleLifecycleGeneration(ctx)) return;\n\n if (ev?.success !== false) {\n try {\n const messages = ev?.messages ?? [];\n let guard = evaluatePreFinalizationGuard(messages, { sessionKey: sessionId });\n const requiresProjectFacts =\n guard.reason === \"missing_checkpoint_block\" || guard.reason === \"missing_checkpoint_warn\";\n if (requiresProjectFacts) {\n const projectFacts = ctx.factsDb.listFactsByCategory(TASK_LEDGER_CATEGORY, 8000);\n guard = evaluatePreFinalizationGuard(messages, { projectFacts, sessionKey: sessionId });\n }\n const guardMessage = formatPreFinalizationGuardMessage(guard);\n if (guard.reason === \"explicit_bypass\" || guard.reason === \"checkpoint_present\") {\n api.logger.info?.(`memory-hybrid: ${guardMessage}`);\n } else if (guard.action === \"warn\") {\n api.logger.warn?.(`memory-hybrid: ${guardMessage}`);\n } else if (guard.action === \"block\") {\n api.logger.warn?.(`memory-hybrid: ${guardMessage}`);\n try {\n ctx.auditStore?.append({\n agentId: ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:pre-finalization-guard-advisory\",\n outcome: \"partial\",\n context: {\n missingFields: guard.checkpoint.missingFields,\n signals: guard.signals,\n },\n });\n } catch (auditErr) {\n api.logger.debug?.(`memory-hybrid: audit store append failed (non-fatal): ${String(auditErr)}`);\n }\n // agent_end is fail-open in OpenClaw core (hook-runner-global), so throwing here\n // only produces a spurious error-level log without actually blocking finalization.\n // Log the advisory at warn level only (#1479 Fix D).\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: pre-finalization guard skipped (non-fatal): ${String(err)}`);\n }\n }\n });\n };\n\n const dispose = getDispose(staleSweepTimer, sessionState);\n\n return { onAgentStart, onAgentEnd, onFrustrationDetect, dispose, sessionState };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hooks.js","names":[],"sources":["../../lifecycle/hooks.ts"],"sourcesContent":["import { getEnv } from \"../utils/env-manager.js\";\n/**\n * Lifecycle Hooks (Phase 2.3: staged pipeline).\n *\n * Dispatcher: registers before_agent_start, agent_end, and frustration handlers (subagent hooks: stage-cleanup).\n * All stage logic lives in stage-*.ts and session-state.ts; this file stays <200 lines.\n */\n\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../config/index.js\";\nimport { isAbortOrTransientLlmError } from \"../services/chat.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildDailyNarrative } from \"../src/worker/narratives.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { createSessionState } from \"./session-state.js\";\nimport { registerActiveTaskInjection } from \"./stage-active-task.js\";\nimport { registerAuthFailureRecall } from \"./stage-auth-failure.js\";\nimport { runCaptureStage } from \"./stage-capture.js\";\nimport { createStaleSweepTimer, getDispose, registerCleanupHandlers } from \"./stage-cleanup.js\";\nimport { registerCredentialHint } from \"./stage-credential-hint.js\";\nimport { registerFrustrationHandlers } from \"./stage-frustration.js\";\nimport { registerGoalStewardshipInjection, resolvedGoalsDirForLifecycle } from \"./stage-goal-stewardship.js\";\nimport { registerGoalSubagentHandlers } from \"./stage-goal-subagent.js\";\nimport { runInjectionStage } from \"./stage-injection.js\";\nimport { runRecallStage } from \"./stage-recall.js\";\nimport { runSetupStage } from \"./stage-setup.js\";\nimport { formatPreFinalizationGuardMessage, evaluatePreFinalizationGuard } from \"../services/pre-finalization-guard.js\";\nimport { TASK_LEDGER_CATEGORY } from \"../services/task-ledger-facts.js\";\nimport { isRecallContextSuperseded, suppressStaleLifecycleDbError } from \"../utils/registration-superseded.js\";\nimport type { LifecycleContext } from \"./types.js\";\nimport { isStaleLifecycleGeneration } from \"../utils/lifecycle-generation.js\";\n\nexport type { LifecycleContext } from \"./types.js\";\n\nexport function createLifecycleHooks(ctx: LifecycleContext) {\n const sessionState = createSessionState();\n const staleSweepTimer = createStaleSweepTimer(sessionState);\n let firstRecallCheckpointCaptured = false;\n\n const workspaceRoot = getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n const resolvedActiveTaskPath = isAbsolute(ctx.cfg.activeTask.filePath)\n ? ctx.cfg.activeTask.filePath\n : join(workspaceRoot, ctx.cfg.activeTask.filePath);\n\n const onAgentStart = (api: ClawdbotPluginApi) => {\n // OpenClaw typed hooks: (event, PluginHookAgentContext). Second arg must be declared so\n // sessionKey/sessionId/agentId reach resolvers via withHookResolutionApi (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n await runSetupStage(event, rApi, ctx, sessionState);\n });\n\n if (ctx.cfg.autoRecall.enabled) {\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const shouldCaptureFirstRecall = !firstRecallCheckpointCaptured;\n const capturedFirstRecallBegin =\n shouldCaptureFirstRecall &&\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.begin\",\n onceKey: \"startup.first-recall.begin\",\n }) !== null;\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = true;\n }\n try {\n const recallStageResult = await runRecallStage(event, rApi, ctx, sessionState);\n if (isStaleLifecycleGeneration(ctx)) {\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = false;\n }\n return undefined;\n }\n if (!recallStageResult) {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: \"timeout\",\n },\n });\n }\n return undefined;\n }\n if (recallStageResult.kind === \"degraded\") {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return { prependContext: recallStageResult.prependContext };\n }\n if (recallStageResult.kind === \"empty\") {\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return recallStageResult.prependContext ? { prependContext: recallStageResult.prependContext } : undefined;\n }\n const inj = await runInjectionStage(recallStageResult.result, rApi, ctx, event);\n if (isStaleLifecycleGeneration(ctx)) {\n if (capturedFirstRecallBegin) {\n firstRecallCheckpointCaptured = false;\n }\n return undefined;\n }\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.after\",\n onceKey: \"startup.first-recall.after\",\n tags: {\n resultKind: recallStageResult.kind,\n },\n });\n }\n return inj ?? undefined;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (\n isStaleLifecycleGeneration(ctx) &&\n /not open|connection is not open|database is not open/i.test(message)\n ) {\n api.logger.debug?.(\"memory-hybrid: recall skipped (stale lifecycle generation)\");\n return undefined;\n }\n if (isRecallContextSuperseded(ctx)) {\n api.logger.debug?.(\"memory-hybrid: recall skipped (registration superseded during reload)\");\n return undefined;\n }\n if (\n suppressStaleLifecycleDbError(\n ctx,\n err,\n api.logger,\n \"memory-hybrid: recall skipped (database closed during reload)\",\n )\n ) {\n return undefined;\n }\n if (capturedFirstRecallBegin) {\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"auto-recall\",\n operation: \"first-recall\",\n phase: \"startup.first-recall.error\",\n onceKey: \"startup.first-recall.error\",\n tags: {\n error: err instanceof Error ? err.name : \"unknown\",\n },\n });\n }\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"recall\",\n subsystem: \"auto-recall\",\n });\n api.logger.warn(`memory-hybrid: recall failed: ${String(err)}`);\n }\n return undefined;\n });\n }\n\n registerActiveTaskInjection(api, ctx, resolvedActiveTaskPath, workspaceRoot);\n const resolvedGoalsDir = resolvedGoalsDirForLifecycle(ctx.cfg);\n registerGoalStewardshipInjection(\n api,\n ctx,\n resolvedGoalsDir,\n ctx.cfg.activeTask.enabled ? resolvedActiveTaskPath : undefined,\n );\n registerGoalSubagentHandlers(api, ctx, resolvedGoalsDir);\n registerCleanupHandlers(api, ctx, sessionState, resolvedActiveTaskPath, workspaceRoot);\n // Guard experimental/optional features at the registration point — avoids registering\n // event listeners whose bodies immediately return when disabled (#581).\n if (ctx.cfg.autoRecall.enabled && ctx.cfg.autoRecall.authFailure.enabled) {\n registerAuthFailureRecall(api, ctx, sessionState);\n }\n // Note: credential hints are gated on verbosity !== \"silent\" because their output\n // (a prepended hint block) is meaningless in silent mode. This is intentional:\n // the feature adds context only when the agent can surface it. If credential detection\n // without output injection is ever needed, split the guard accordingly.\n if (ctx.cfg.credentials.enabled && ctx.cfg.credentials.autoDetect && ctx.cfg.verbosity !== \"silent\") {\n registerCredentialHint(api, ctx);\n }\n };\n\n const onFrustrationDetect = (api: ClawdbotPluginApi) => {\n registerFrustrationHandlers(api, ctx, sessionState);\n };\n\n const onAgentEnd = (api: ClawdbotPluginApi) => {\n // Same typed-hook shape as before_agent_start (#1005).\n api.on(\"agent_end\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const ev = event as { messages?: unknown[]; success?: boolean };\n\n if (isStaleLifecycleGeneration(ctx)) return;\n\n // Issue #742: extract tool names from messages and record via WorkflowTracker\n // so crystallization can detect patterns from the traces table.\n if (ctx.workflowTracker && ctx.cfg.workflowTracking?.enabled) {\n try {\n const messages = ev?.messages ?? [];\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n\n // Extract goal from first user message (used as trace label)\n let goal = \"unknown\";\n for (const msg of messages) {\n if (msg && typeof msg === \"object\" && (msg as { role?: string }).role === \"user\") {\n const content = (msg as { content?: unknown }).content;\n if (typeof content === \"string\" && content.trim()) {\n goal = content.trim().slice(0, 200);\n break;\n }\n }\n }\n\n // Get session start time from sessionLastActivity (set during before_agent_start)\n const sessionStartTime = sessionState.sessionLastActivity.get(sessionId);\n\n // Push each tool call onto the tracker buffer with the actual session start time\n for (const msg of messages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n if (msgObj.role !== \"assistant\") continue;\n const toolCalls = msgObj.tool_calls;\n if (!Array.isArray(toolCalls)) continue;\n for (const tc of toolCalls) {\n if (!tc || typeof tc !== \"object\") continue;\n const fn = (tc as Record<string, unknown>).function as Record<string, unknown> | undefined;\n if (fn && typeof fn.name === \"string\") {\n ctx.workflowTracker?.push(sessionId, fn.name, sessionStartTime);\n }\n }\n }\n\n // Flush buffer to workflow-traces.db\n const outcome = ev?.success === true ? \"success\" : ev?.success === false ? \"failure\" : \"unknown\";\n const traceId = ctx.workflowTracker?.flush(sessionId, goal, outcome);\n if (traceId) {\n api.logger.debug?.(`memory-hybrid: workflow trace recorded id=${traceId} session=${sessionId}`);\n }\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"workflow-tracking\",\n operation: \"agent-end-track-workflow\",\n sessionId: sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\",\n });\n api.logger.warn(`memory-hybrid: workflow tracking failed: ${String(err)}`);\n }\n }\n\n if (isStaleLifecycleGeneration(ctx)) {\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n sessionState.clearSessionState(sessionId);\n return;\n }\n await runCaptureStage(event, rApi, ctx, sessionState);\n if (isStaleLifecycleGeneration(ctx)) return;\n const sessionId = sessionState.resolveSessionKey(event, rApi) ?? ctx.currentAgentIdRef.value ?? \"default\";\n if (isStaleLifecycleGeneration(ctx)) return;\n if (ctx.cfg.goalStewardship?.enabled) {\n try {\n const { listActiveGoals, resolveGoalsDir } = await import(\"../services/goal-stewardship.js\");\n const gDir = resolveGoalsDir(workspaceRoot, ctx.cfg.goalStewardship.goalsDir);\n const activeGoals = await listActiveGoals(gDir);\n if (activeGoals.length > 0) {\n api.logger.debug?.(\n `memory-hybrid: active goals at session end: ${activeGoals.map((g) => `${g.label}(${g.status})`).join(\", \")}`,\n );\n try {\n ctx.eventLog?.append({\n sessionId,\n timestamp: new Date().toISOString(),\n eventType: \"action_taken\",\n content: {\n kind: \"goal.session_summary\",\n activeGoals: activeGoals.map((g) => ({\n id: g.id,\n label: g.label,\n status: g.status,\n assessments: g.assessmentCount,\n })),\n },\n });\n } catch {\n /* non-fatal */\n }\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: goal session summary failed (non-fatal): ${String(err)}`);\n }\n }\n if (isStaleLifecycleGeneration(ctx)) return;\n\n try {\n await buildDailyNarrative({\n sessionId,\n eventLog: ctx.eventLog,\n workflowStore: ctx.workflowStore,\n narrativesDb: ctx.narrativesDb,\n openai: ctx.openai,\n model: getDefaultCronModel(getCronModelConfig(ctx.cfg), \"nano\"),\n logger: api.logger,\n fallbackModels: [],\n registrationGeneration: ctx.registrationGeneration,\n currentRegistrationGenerationRef: ctx.currentRegistrationGenerationRef,\n });\n } catch (err) {\n const transient = isAbortOrTransientLlmError(err);\n if (!transient) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"narratives\",\n operation: \"agent-end-build-narrative\",\n sessionId,\n });\n }\n const detail = err instanceof Error ? err.message : String(err);\n if (transient) {\n api.logger.info?.(`memory-hybrid: session narrative skipped (LLM unavailable or aborted): ${detail}`);\n } else {\n api.logger.warn(`memory-hybrid: session narrative build failed: ${String(err)}`);\n }\n }\n if (isStaleLifecycleGeneration(ctx)) return;\n\n if (ev?.success !== false) {\n try {\n const messages = ev?.messages ?? [];\n let guard = evaluatePreFinalizationGuard(messages, { sessionKey: sessionId });\n const requiresProjectFacts =\n guard.reason === \"missing_checkpoint_block\" || guard.reason === \"missing_checkpoint_warn\";\n if (requiresProjectFacts) {\n const projectFacts = ctx.factsDb.listFactsByCategory(TASK_LEDGER_CATEGORY, 8000);\n guard = evaluatePreFinalizationGuard(messages, { projectFacts, sessionKey: sessionId });\n }\n const guardMessage = formatPreFinalizationGuardMessage(guard);\n if (guard.reason === \"explicit_bypass\" || guard.reason === \"checkpoint_present\") {\n api.logger.info?.(`memory-hybrid: ${guardMessage}`);\n } else if (guard.action === \"warn\") {\n api.logger.warn?.(`memory-hybrid: ${guardMessage}`);\n } else if (guard.action === \"block\") {\n api.logger.warn?.(`memory-hybrid: ${guardMessage}`);\n try {\n ctx.auditStore?.append({\n agentId: ctx.currentAgentIdRef.value ?? \"unknown\",\n action: \"cleanup:pre-finalization-guard-advisory\",\n outcome: \"partial\",\n context: {\n missingFields: guard.checkpoint.missingFields,\n signals: guard.signals,\n },\n });\n } catch (auditErr) {\n api.logger.debug?.(`memory-hybrid: audit store append failed (non-fatal): ${String(auditErr)}`);\n }\n // agent_end is fail-open in OpenClaw core (hook-runner-global), so throwing here\n // only produces a spurious error-level log without actually blocking finalization.\n // Log the advisory at warn level only (#1479 Fix D).\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: pre-finalization guard skipped (non-fatal): ${String(err)}`);\n }\n }\n });\n };\n\n const dispose = getDispose(staleSweepTimer, sessionState);\n\n return { onAgentStart, onAgentEnd, onFrustrationDetect, dispose, sessionState };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-agent-id.js","names":[],"sources":["../../lifecycle/resolve-agent-id.ts"],"sourcesContent":["/**\n * Resolve the active agent id for lifecycle hooks (`before_agent_start`, etc.).\n *\n * OpenClaw should populate `api.context.agentId` for routed channels; some builds\n * only pass identity on the event payload. This module centralizes best-effort\n * extraction so WhatsApp and similar routes can be recognized without duplicating\n * ad-hoc field checks across stages.\n *\n * Cron / embedded runs may omit structured `agentId` while still using session keys\n * like `agent:<id>:cron:<jobId>` — see #990 and `tryParseAgentIdFromOpenClawSessionKey`.\n *\n * **Precedence (explicit id, first hit wins):** event/session/run/payload `agentId` fields,\n * then `api.context.agentId` (include values merged from typed-hook context via\n * `withHookResolutionApi`). Finally, derive from the session key produced by\n * `resolveSessionKeyFromHookEvent` (`tryParseAgentIdFromOpenClawSessionKey`). This matches\n * session-key resolution: structured event beats hook-sourced `api.context`, then fallbacks.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { resolveSessionKeyFromHookEvent } from \"./session-state.js\";\n\nconst SESSION_KEY_TRUNCATE_MAX = 120;\n\nfunction nonEmptyString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const t = v.trim();\n return t.length > 0 ? t : null;\n}\n\nexport function formatSessionKeyTruncated(sessionKey: string): string {\n if (sessionKey.length <= SESSION_KEY_TRUNCATE_MAX) return sessionKey;\n return `${sessionKey.slice(0, SESSION_KEY_TRUNCATE_MAX - 3)}...`;\n}\n\n/**\n * Parse OpenClaw-style session keys: `agent:<agentId>:<suffix...>`\n * (e.g. `agent:main:main`, `agent:ralph:cron:job-1`, `agent:forge:subagent:uuid`).\n *\n * @returns The agent id segment, or `null` if the key does not match (including\n * bare `cron:<jobId>` keys, which carry no agent prefix).\n */\nexport function tryParseAgentIdFromOpenClawSessionKey(sessionKey: string): string | null {\n const t = sessionKey.trim();\n if (!t.startsWith(\"agent:\")) return null;\n const parts = t.split(\":\");\n if (parts.length < 3) return null;\n const id = parts[1]?.trim();\n return id && id.length > 0 ? id : null;\n}\n\n/**\n * @returns Detected agent id, or `null` if nothing usable was found.\n */\nexport function resolveAgentIdFromHookEvent(event: unknown, api: ClawdbotPluginApi): string | null {\n const ev = event as Record<string, unknown>;\n const session = ev.session as Record<string, unknown> | undefined;\n const run = ev.run as Record<string, unknown> | undefined;\n const payloadCtx = ev.context as Record<string, unknown> | undefined;\n const activeAgent = session?.activeAgent;\n\n const explicit =\n nonEmptyString(ev.agentId) ??\n nonEmptyString(session?.agentId) ??\n nonEmptyString(session?.agent) ??\n nonEmptyString(session?.activeAgentId) ??\n nonEmptyString(session?.botId) ??\n nonEmptyString(session?.routedAgentId) ??\n (activeAgent && typeof activeAgent === \"object\"\n ? nonEmptyString((activeAgent as Record<string, unknown>).id)\n : null) ??\n nonEmptyString(run?.agentId) ??\n nonEmptyString(payloadCtx?.agentId) ??\n nonEmptyString(api.context?.agentId);\n\n if (explicit) return explicit;\n\n const sessionKey = resolveSessionKeyFromHookEvent(event, api);\n const fromSessionKey = sessionKey ? tryParseAgentIdFromOpenClawSessionKey(sessionKey) : null;\n if (fromSessionKey && sessionKey) {\n api.logger?.debug?.(\n `memory-hybrid: Resolved agentId \"${fromSessionKey}\" from session key pattern (${formatSessionKeyTruncated(sessionKey)})`,\n );\n }\n return fromSessionKey;\n}\n"],"mappings":";;AAqBA,MAAM,2BAA2B;AAEjC,SAAS,eAAe,GAA2B;CACjD,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,MAAM,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"resolve-agent-id.js","names":[],"sources":["../../lifecycle/resolve-agent-id.ts"],"sourcesContent":["/**\n * Resolve the active agent id for lifecycle hooks (`before_agent_start`, etc.).\n *\n * OpenClaw should populate `api.context.agentId` for routed channels; some builds\n * only pass identity on the event payload. This module centralizes best-effort\n * extraction so WhatsApp and similar routes can be recognized without duplicating\n * ad-hoc field checks across stages.\n *\n * Cron / embedded runs may omit structured `agentId` while still using session keys\n * like `agent:<id>:cron:<jobId>` — see #990 and `tryParseAgentIdFromOpenClawSessionKey`.\n *\n * **Precedence (explicit id, first hit wins):** event/session/run/payload `agentId` fields,\n * then `api.context.agentId` (include values merged from typed-hook context via\n * `withHookResolutionApi`). Finally, derive from the session key produced by\n * `resolveSessionKeyFromHookEvent` (`tryParseAgentIdFromOpenClawSessionKey`). This matches\n * session-key resolution: structured event beats hook-sourced `api.context`, then fallbacks.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport { resolveSessionKeyFromHookEvent } from \"./session-state.js\";\n\nconst SESSION_KEY_TRUNCATE_MAX = 120;\n\nfunction nonEmptyString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const t = v.trim();\n return t.length > 0 ? t : null;\n}\n\nexport function formatSessionKeyTruncated(sessionKey: string): string {\n if (sessionKey.length <= SESSION_KEY_TRUNCATE_MAX) return sessionKey;\n return `${sessionKey.slice(0, SESSION_KEY_TRUNCATE_MAX - 3)}...`;\n}\n\n/**\n * Parse OpenClaw-style session keys: `agent:<agentId>:<suffix...>`\n * (e.g. `agent:main:main`, `agent:ralph:cron:job-1`, `agent:forge:subagent:uuid`).\n *\n * @returns The agent id segment, or `null` if the key does not match (including\n * bare `cron:<jobId>` keys, which carry no agent prefix).\n */\nexport function tryParseAgentIdFromOpenClawSessionKey(sessionKey: string): string | null {\n const t = sessionKey.trim();\n if (!t.startsWith(\"agent:\")) return null;\n const parts = t.split(\":\");\n if (parts.length < 3) return null;\n const id = parts[1]?.trim();\n return id && id.length > 0 ? id : null;\n}\n\n/**\n * @returns Detected agent id, or `null` if nothing usable was found.\n */\nexport function resolveAgentIdFromHookEvent(event: unknown, api: ClawdbotPluginApi): string | null {\n const ev = event as Record<string, unknown>;\n const session = ev.session as Record<string, unknown> | undefined;\n const run = ev.run as Record<string, unknown> | undefined;\n const payloadCtx = ev.context as Record<string, unknown> | undefined;\n const activeAgent = session?.activeAgent;\n\n const explicit =\n nonEmptyString(ev.agentId) ??\n nonEmptyString(session?.agentId) ??\n nonEmptyString(session?.agent) ??\n nonEmptyString(session?.activeAgentId) ??\n nonEmptyString(session?.botId) ??\n nonEmptyString(session?.routedAgentId) ??\n (activeAgent && typeof activeAgent === \"object\"\n ? nonEmptyString((activeAgent as Record<string, unknown>).id)\n : null) ??\n nonEmptyString(run?.agentId) ??\n nonEmptyString(payloadCtx?.agentId) ??\n nonEmptyString(api.context?.agentId);\n\n if (explicit) return explicit;\n\n const sessionKey = resolveSessionKeyFromHookEvent(event, api);\n const fromSessionKey = sessionKey ? tryParseAgentIdFromOpenClawSessionKey(sessionKey) : null;\n if (fromSessionKey && sessionKey) {\n api.logger?.debug?.(\n `memory-hybrid: Resolved agentId \"${fromSessionKey}\" from session key pattern (${formatSessionKeyTruncated(sessionKey)})`,\n );\n }\n return fromSessionKey;\n}\n"],"mappings":";;AAqBA,MAAM,2BAA2B;AAEjC,SAAS,eAAe,GAA2B;CACjD,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,MAAM,IAAI,EAAE,KAAK;CACjB,OAAO,EAAE,SAAS,IAAI,IAAI;AAC5B;AAEA,SAAgB,0BAA0B,YAA4B;CACpE,IAAI,WAAW,UAAU,0BAA0B,OAAO;CAC1D,OAAO,GAAG,WAAW,MAAM,GAAG,2BAA2B,CAAC,EAAE;AAC9D;;;;;;;;AASA,SAAgB,sCAAsC,YAAmC;CACvF,MAAM,IAAI,WAAW,KAAK;CAC1B,IAAI,CAAC,EAAE,WAAW,QAAQ,GAAG,OAAO;CACpC,MAAM,QAAQ,EAAE,MAAM,GAAG;CACzB,IAAI,MAAM,SAAS,GAAG,OAAO;CAC7B,MAAM,KAAK,MAAM,IAAI,KAAK;CAC1B,OAAO,MAAM,GAAG,SAAS,IAAI,KAAK;AACpC;;;;AAKA,SAAgB,4BAA4B,OAAgB,KAAuC;CACjG,MAAM,KAAK;CACX,MAAM,UAAU,GAAG;CACnB,MAAM,MAAM,GAAG;CACf,MAAM,aAAa,GAAG;CACtB,MAAM,cAAc,SAAS;CAE7B,MAAM,WACJ,eAAe,GAAG,OAAO,KACzB,eAAe,SAAS,OAAO,KAC/B,eAAe,SAAS,KAAK,KAC7B,eAAe,SAAS,aAAa,KACrC,eAAe,SAAS,KAAK,KAC7B,eAAe,SAAS,aAAa,MACpC,eAAe,OAAO,gBAAgB,WACnC,eAAgB,YAAwC,EAAE,IAC1D,SACJ,eAAe,KAAK,OAAO,KAC3B,eAAe,YAAY,OAAO,KAClC,eAAe,IAAI,SAAS,OAAO;CAErC,IAAI,UAAU,OAAO;CAErB,MAAM,aAAa,+BAA+B,OAAO,GAAG;CAC5D,MAAM,iBAAiB,aAAa,sCAAsC,UAAU,IAAI;CACxF,IAAI,kBAAkB,YACpB,IAAI,QAAQ,QACV,oCAAoC,eAAe,8BAA8B,0BAA0B,UAAU,EAAE,EACzH;CAEF,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-state.js","names":[],"sources":["../../lifecycle/session-state.ts"],"sourcesContent":["/**\n * Session state for the lifecycle pipeline (Phase 2.3).\n * Creates per-session maps and helpers: touchSession, clearSessionState, pruneSessionMaps, resolveSessionKey.\n *\n * Typed-hook identity (`PluginHookAgentContext`) is merged into `api` at the dispatcher via\n * `withHookResolutionApi` in `hook-resolution-api.ts` (#1005).\n */\n\nimport type { SessionSeenFacts } from \"../services/ambient-retrieval.js\";\nimport type { FrustrationConversationTurn } from \"../services/frustration-detector.js\";\nimport type { SessionState } from \"./types.js\";\n\nconst MAX_TRACKED_SESSIONS = 200;\n\n/** API slice used when resolving the current session key from a hook event (#990). */\nexport type SessionKeyHookApi = { context?: { sessionId?: string; sessionKey?: string } };\n\n/**\n * Best-effort session key string for lifecycle hooks — same precedence as\n * {@link createSessionState}'s `resolveSessionKey` (exported for agent id parsing and tests).\n *\n * **Precedence (first hit wins):** `event.session` / top-level session-ish fields /\n * `event.context`, then `api.context.sessionId`, then `api.context.sessionKey`.\n * Callers pass `withHookResolutionApi(api, hookCtx)` so hook `sessionId`/`sessionKey` land on\n * `api.context` and are consulted only after the event payload (#1005).\n */\nexport function resolveSessionKeyFromHookEvent(event: unknown, api?: SessionKeyHookApi): string | null {\n const ev = event as {\n session?: Record<string, unknown>;\n sessionKey?: string;\n context?: Record<string, unknown>;\n };\n const payloadCtx = ev?.context;\n const sessionId =\n ev?.session?.id ??\n ev?.session?.sessionId ??\n ev?.session?.key ??\n ev?.session?.label ??\n ev?.sessionKey ??\n (payloadCtx?.sessionId as string | undefined) ??\n (payloadCtx?.sessionKey as string | undefined) ??\n (payloadCtx?.key as string | undefined) ??\n (payloadCtx?.id as string | undefined) ??\n (payloadCtx?.label as string | undefined) ??\n api?.context?.sessionId ??\n api?.context?.sessionKey ??\n null;\n return sessionId ? String(sessionId) : null;\n}\n\nexport function createSessionState(): SessionState {\n const authFailureRecallsThisSession = new Map<string, number>();\n const sessionStartSeen = new Set<string>();\n const frustrationStateMap = new Map<string, { level: number; turns: FrustrationConversationTurn[] }>();\n const ambientSeenFactsMap = new Map<string, SessionSeenFacts>();\n const ambientLastEmbeddingMap = new Map<string, number[] | null>();\n const sessionLastActivity = new Map<string, number>();\n const capabilityHintsSessionsSeen = new Set<string>();\n\n function touchSession(sessionKey: string): void {\n sessionLastActivity.set(sessionKey, Date.now());\n }\n\n function clearSessionState(sessionKey: string): void {\n sessionStartSeen.delete(sessionKey);\n ambientSeenFactsMap.delete(sessionKey);\n ambientLastEmbeddingMap.delete(sessionKey);\n frustrationStateMap.delete(sessionKey);\n sessionLastActivity.delete(sessionKey);\n // Do NOT clear capabilityHintsSessionsSeen here — that set persists across agent turns\n // within the same chat session so \"session\" mode injects once per chat, not once per turn.\n const prefix = `${sessionKey}:`;\n for (const key of authFailureRecallsThisSession.keys()) {\n if (key.startsWith(prefix)) authFailureRecallsThisSession.delete(key);\n }\n }\n\n function pruneSessionMaps(): void {\n if (ambientSeenFactsMap.size > MAX_TRACKED_SESSIONS) {\n const excess = ambientSeenFactsMap.size - MAX_TRACKED_SESSIONS;\n const keys = ambientSeenFactsMap.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) {\n ambientSeenFactsMap.delete(value);\n ambientLastEmbeddingMap.delete(value);\n }\n }\n }\n if (frustrationStateMap.size > MAX_TRACKED_SESSIONS) {\n const excess = frustrationStateMap.size - MAX_TRACKED_SESSIONS;\n const keys = frustrationStateMap.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) frustrationStateMap.delete(value);\n }\n }\n if (sessionStartSeen.size > MAX_TRACKED_SESSIONS) {\n const excess = sessionStartSeen.size - MAX_TRACKED_SESSIONS;\n const keys = sessionStartSeen.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) sessionStartSeen.delete(value);\n }\n }\n if (capabilityHintsSessionsSeen.size > MAX_TRACKED_SESSIONS) {\n const excess = capabilityHintsSessionsSeen.size - MAX_TRACKED_SESSIONS;\n const keys = capabilityHintsSessionsSeen.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) capabilityHintsSessionsSeen.delete(value);\n }\n }\n if (authFailureRecallsThisSession.size > MAX_TRACKED_SESSIONS * 3) {\n const excess = authFailureRecallsThisSession.size - MAX_TRACKED_SESSIONS * 3;\n const keys = authFailureRecallsThisSession.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) authFailureRecallsThisSession.delete(value);\n }\n }\n if (sessionLastActivity.size > MAX_TRACKED_SESSIONS) {\n const excess = sessionLastActivity.size - MAX_TRACKED_SESSIONS;\n const keys = sessionLastActivity.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) sessionLastActivity.delete(value);\n }\n }\n }\n\n function resolveSessionKey(event: unknown, api?: SessionKeyHookApi): string | null {\n return resolveSessionKeyFromHookEvent(event, api);\n }\n\n const clearAll = (): void => {\n sessionStartSeen.clear();\n ambientSeenFactsMap.clear();\n ambientLastEmbeddingMap.clear();\n frustrationStateMap.clear();\n authFailureRecallsThisSession.clear();\n sessionLastActivity.clear();\n capabilityHintsSessionsSeen.clear();\n };\n\n return {\n sessionStartSeen,\n ambientSeenFactsMap,\n ambientLastEmbeddingMap,\n frustrationStateMap,\n authFailureRecallsThisSession,\n sessionLastActivity,\n capabilityHintsSessionsSeen,\n touchSession,\n clearSessionState,\n pruneSessionMaps,\n resolveSessionKey,\n MAX_TRACKED_SESSIONS,\n clearAll,\n };\n}\n"],"mappings":";AAYA,MAAM,uBAAuB;;;;;;;;;;AAc7B,SAAgB,+BAA+B,OAAgB,KAAwC;CACrG,MAAM,KAAK;CAKX,MAAM,aAAa,IAAI;CACvB,MAAM,YACJ,IAAI,SAAS,MACb,IAAI,SAAS,aACb,IAAI,SAAS,OACb,IAAI,SAAS,SACb,IAAI,cACH,YAAY,aACZ,YAAY,cACZ,YAAY,OACZ,YAAY,MACZ,YAAY,SACb,KAAK,SAAS,aACd,KAAK,SAAS,cACd;CACF,OAAO,YAAY,OAAO,
|
|
1
|
+
{"version":3,"file":"session-state.js","names":[],"sources":["../../lifecycle/session-state.ts"],"sourcesContent":["/**\n * Session state for the lifecycle pipeline (Phase 2.3).\n * Creates per-session maps and helpers: touchSession, clearSessionState, pruneSessionMaps, resolveSessionKey.\n *\n * Typed-hook identity (`PluginHookAgentContext`) is merged into `api` at the dispatcher via\n * `withHookResolutionApi` in `hook-resolution-api.ts` (#1005).\n */\n\nimport type { SessionSeenFacts } from \"../services/ambient-retrieval.js\";\nimport type { FrustrationConversationTurn } from \"../services/frustration-detector.js\";\nimport type { SessionState } from \"./types.js\";\n\nconst MAX_TRACKED_SESSIONS = 200;\n\n/** API slice used when resolving the current session key from a hook event (#990). */\nexport type SessionKeyHookApi = { context?: { sessionId?: string; sessionKey?: string } };\n\n/**\n * Best-effort session key string for lifecycle hooks — same precedence as\n * {@link createSessionState}'s `resolveSessionKey` (exported for agent id parsing and tests).\n *\n * **Precedence (first hit wins):** `event.session` / top-level session-ish fields /\n * `event.context`, then `api.context.sessionId`, then `api.context.sessionKey`.\n * Callers pass `withHookResolutionApi(api, hookCtx)` so hook `sessionId`/`sessionKey` land on\n * `api.context` and are consulted only after the event payload (#1005).\n */\nexport function resolveSessionKeyFromHookEvent(event: unknown, api?: SessionKeyHookApi): string | null {\n const ev = event as {\n session?: Record<string, unknown>;\n sessionKey?: string;\n context?: Record<string, unknown>;\n };\n const payloadCtx = ev?.context;\n const sessionId =\n ev?.session?.id ??\n ev?.session?.sessionId ??\n ev?.session?.key ??\n ev?.session?.label ??\n ev?.sessionKey ??\n (payloadCtx?.sessionId as string | undefined) ??\n (payloadCtx?.sessionKey as string | undefined) ??\n (payloadCtx?.key as string | undefined) ??\n (payloadCtx?.id as string | undefined) ??\n (payloadCtx?.label as string | undefined) ??\n api?.context?.sessionId ??\n api?.context?.sessionKey ??\n null;\n return sessionId ? String(sessionId) : null;\n}\n\nexport function createSessionState(): SessionState {\n const authFailureRecallsThisSession = new Map<string, number>();\n const sessionStartSeen = new Set<string>();\n const frustrationStateMap = new Map<string, { level: number; turns: FrustrationConversationTurn[] }>();\n const ambientSeenFactsMap = new Map<string, SessionSeenFacts>();\n const ambientLastEmbeddingMap = new Map<string, number[] | null>();\n const sessionLastActivity = new Map<string, number>();\n const capabilityHintsSessionsSeen = new Set<string>();\n\n function touchSession(sessionKey: string): void {\n sessionLastActivity.set(sessionKey, Date.now());\n }\n\n function clearSessionState(sessionKey: string): void {\n sessionStartSeen.delete(sessionKey);\n ambientSeenFactsMap.delete(sessionKey);\n ambientLastEmbeddingMap.delete(sessionKey);\n frustrationStateMap.delete(sessionKey);\n sessionLastActivity.delete(sessionKey);\n // Do NOT clear capabilityHintsSessionsSeen here — that set persists across agent turns\n // within the same chat session so \"session\" mode injects once per chat, not once per turn.\n const prefix = `${sessionKey}:`;\n for (const key of authFailureRecallsThisSession.keys()) {\n if (key.startsWith(prefix)) authFailureRecallsThisSession.delete(key);\n }\n }\n\n function pruneSessionMaps(): void {\n if (ambientSeenFactsMap.size > MAX_TRACKED_SESSIONS) {\n const excess = ambientSeenFactsMap.size - MAX_TRACKED_SESSIONS;\n const keys = ambientSeenFactsMap.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) {\n ambientSeenFactsMap.delete(value);\n ambientLastEmbeddingMap.delete(value);\n }\n }\n }\n if (frustrationStateMap.size > MAX_TRACKED_SESSIONS) {\n const excess = frustrationStateMap.size - MAX_TRACKED_SESSIONS;\n const keys = frustrationStateMap.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) frustrationStateMap.delete(value);\n }\n }\n if (sessionStartSeen.size > MAX_TRACKED_SESSIONS) {\n const excess = sessionStartSeen.size - MAX_TRACKED_SESSIONS;\n const keys = sessionStartSeen.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) sessionStartSeen.delete(value);\n }\n }\n if (capabilityHintsSessionsSeen.size > MAX_TRACKED_SESSIONS) {\n const excess = capabilityHintsSessionsSeen.size - MAX_TRACKED_SESSIONS;\n const keys = capabilityHintsSessionsSeen.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) capabilityHintsSessionsSeen.delete(value);\n }\n }\n if (authFailureRecallsThisSession.size > MAX_TRACKED_SESSIONS * 3) {\n const excess = authFailureRecallsThisSession.size - MAX_TRACKED_SESSIONS * 3;\n const keys = authFailureRecallsThisSession.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) authFailureRecallsThisSession.delete(value);\n }\n }\n if (sessionLastActivity.size > MAX_TRACKED_SESSIONS) {\n const excess = sessionLastActivity.size - MAX_TRACKED_SESSIONS;\n const keys = sessionLastActivity.keys();\n for (let i = 0; i < excess; i++) {\n const { value } = keys.next();\n if (value) sessionLastActivity.delete(value);\n }\n }\n }\n\n function resolveSessionKey(event: unknown, api?: SessionKeyHookApi): string | null {\n return resolveSessionKeyFromHookEvent(event, api);\n }\n\n const clearAll = (): void => {\n sessionStartSeen.clear();\n ambientSeenFactsMap.clear();\n ambientLastEmbeddingMap.clear();\n frustrationStateMap.clear();\n authFailureRecallsThisSession.clear();\n sessionLastActivity.clear();\n capabilityHintsSessionsSeen.clear();\n };\n\n return {\n sessionStartSeen,\n ambientSeenFactsMap,\n ambientLastEmbeddingMap,\n frustrationStateMap,\n authFailureRecallsThisSession,\n sessionLastActivity,\n capabilityHintsSessionsSeen,\n touchSession,\n clearSessionState,\n pruneSessionMaps,\n resolveSessionKey,\n MAX_TRACKED_SESSIONS,\n clearAll,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-active-task.js","names":[],"sources":["../../lifecycle/stage-active-task.ts"],"sourcesContent":["/**\n * Lifecycle: active-task injection (Phase 2.3).\n * Registers before_agent_start to inject ACTIVE-TASKS.md summary when enabled.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n detectStaleTasks,\n readActiveTaskFile,\n upsertTask,\n writeActiveTaskFileGuarded,\n} from \"../services/active-task.js\";\nimport { buildActiveTaskContextBundle } from \"../services/active-task-injection.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { listGoals, resolveGoalsDir } from \"../services/goal-registry.js\";\nimport { matchesHeartbeat } from \"../services/goal-stewardship-heartbeat.js\";\nimport {\n buildGoalEscalationHeartbeatBlock,\n buildLongRunningTaskDraft,\n buildLongRunningTaskRegistrationBlock,\n detectLongRunningWorkflowProposal,\n shouldAutoRegisterLongRunningTask,\n} from \"../services/task-hygiene.js\";\nimport { loadTaskLedgerFromFactsWithMetrics, syncActiveTaskEntryToFacts } from \"../services/task-ledger-facts.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport { extractLastUserMessageText } from \"../utils/extract-last-user-message.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { resolveSessionKeyFromHookEvent } from \"./session-state.js\";\nimport type { LifecycleContext } from \"./types.js\";\n\nexport function registerActiveTaskInjection(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n resolvedActiveTaskPath: string,\n workspaceRoot: string,\n): void {\n if (!ctx.cfg.activeTask.enabled || ctx.cfg.verbosity === \"silent\") return;\n let firstActiveTaskProjectionCaptured = false;\n\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n try {\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n let activeForInjection: import(\"../services/active-task.js\").ActiveTaskEntry[] = [];\n let completedForWrite: import(\"../services/active-task.js\").ActiveTaskEntry[] = [];\n const userText = extractLastUserMessageText(event);\n const longRunningMode = ctx.cfg.activeTask.taskHygiene.longRunningRegistration?.mode ?? \"suggest\";\n const proposal =\n userText && longRunningMode !== \"off\" ? detectLongRunningWorkflowProposal(userText, workspaceRoot) : null;\n const resolvedApi = withHookResolutionApi(api, hookCtx);\n const sessionKey = resolveSessionKeyFromHookEvent(event, resolvedApi);\n let factsSelectionMetrics: import(\"../services/task-ledger-facts.js\").ActiveTaskLedgerSelectionMetrics | null =\n null;\n let factsSelectionStartMs: number | null = null;\n let staleSkippedFromFacts = 0;\n\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n factsSelectionStartMs = Date.now();\n const { active, metrics } = loadTaskLedgerFromFactsWithMetrics(ctx.factsDb);\n activeForInjection = detectStaleTasks(active, staleMinutes);\n factsSelectionMetrics = metrics;\n staleSkippedFromFacts = activeForInjection.filter((task) => task.stale).length;\n } else {\n const taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n activeForInjection = taskFile?.active ?? [];\n completedForWrite = taskFile?.completed ?? [];\n }\n\n const logFactsSelection = (injectedCount: number): void => {\n if (!factsSelectionMetrics || factsSelectionStartMs === null) return;\n api.logger?.debug?.(\n `memory-hybrid: active-task selection rowsFetched=${factsSelectionMetrics.projectRowsFetched} groupedEntities=${factsSelectionMetrics.groupedEntityCount} duplicatesCollapsed=${factsSelectionMetrics.duplicateRowsCollapsed} activeCandidates=${factsSelectionMetrics.activeCandidates} staleSkipped=${staleSkippedFromFacts} injected=${injectedCount} elapsedMs=${Date.now() - factsSelectionStartMs}`,\n );\n };\n const logStartupProjectionCheckpoint = (phase: string, injectedCount: number): void => {\n if (firstActiveTaskProjectionCaptured) return;\n firstActiveTaskProjectionCaptured = true;\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"active-task\",\n operation: \"first-projection\",\n phase,\n onceKey: \"startup.first-active-task-projection\",\n tags: {\n ledger: ctx.cfg.activeTask.ledger,\n activeCandidates: activeForInjection.length,\n staleCandidates: staleSkippedFromFacts,\n injectedCount,\n },\n });\n };\n\n let longRunningBlock = \"\";\n if (proposal) {\n const draft = buildLongRunningTaskDraft(proposal);\n const alreadyActive = activeForInjection.some((t) => t.label.toLowerCase() === draft.label.toLowerCase());\n let autoCreated = false;\n\n if (!alreadyActive && shouldAutoRegisterLongRunningTask(longRunningMode, sessionKey)) {\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, draft, api.logger);\n activeForInjection = upsertTask(activeForInjection, draft, true);\n autoCreated = true;\n } else {\n const updated = upsertTask(activeForInjection, draft, true);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n completedForWrite,\n sessionKey ?? undefined,\n );\n if (writeResult.skipped) {\n api.logger?.debug?.(`memory-hybrid: skipped long-running task auto-registration: ${writeResult.reason}`);\n } else {\n activeForInjection = updated;\n autoCreated = true;\n }\n }\n }\n\n longRunningBlock = buildLongRunningTaskRegistrationBlock(proposal, draft, {\n mode: longRunningMode,\n autoCreated,\n alreadyActive,\n sessionKey,\n });\n }\n\n if (activeForInjection.length === 0 && !longRunningBlock) {\n logStartupProjectionCheckpoint(\"startup.first-active-task-projection.empty\", 0);\n logFactsSelection(0);\n return undefined;\n }\n\n const th = ctx.cfg.activeTask.taskHygiene;\n const isHeartbeat =\n th.heartbeatEscalation &&\n ctx.cfg.goalStewardship.enabled &&\n !!userText &&\n matchesHeartbeat(userText, ctx.cfg.goalStewardship);\n\n let goalEscalationPrebuilt = \"\";\n if (\n isHeartbeat &&\n activeForInjection.length > 0 &&\n ctx.cfg.goalStewardship.escalationPolicy.taskHygieneOnBlockedGoals\n ) {\n const goalsDir = resolveGoalsDir(workspaceRoot, ctx.cfg.goalStewardship.goalsDir);\n const goals = await listGoals(goalsDir);\n goalEscalationPrebuilt = buildGoalEscalationHeartbeatBlock(goals, {\n maxChars: Math.min(1200, th.heartbeatNudgeMaxChars),\n });\n }\n\n const bundle = buildActiveTaskContextBundle({\n ledgerTasks: activeForInjection,\n injectionBudgetTokens: ctx.cfg.activeTask.injectionBudget,\n staleMinutes,\n staleWarningEnabled: ctx.cfg.activeTask.staleWarning.enabled,\n projection: ctx.cfg.activeTask.projection,\n injectionMaxTasks: ctx.cfg.activeTask.injectionMaxTasks,\n userText: userText ?? undefined,\n sessionKey: sessionKey ?? undefined,\n heartbeatHygiene:\n isHeartbeat && activeForInjection.length > 0\n ? {\n maxChars: th.heartbeatNudgeMaxChars,\n suggestGoalAfterTaskAgeDays: th.suggestGoalAfterTaskAgeDays,\n }\n : undefined,\n goalEscalationBlock: goalEscalationPrebuilt || undefined,\n });\n\n if (isHeartbeat && bundle.parts.some((p) => p.includes(\"<task-hygiene>\"))) {\n api.logger?.info?.(\"memory-hybrid: task hygiene block appended (heartbeat match)\");\n }\n\n logFactsSelection(bundle.injectedTaskCount);\n logStartupProjectionCheckpoint(\"startup.first-active-task-projection.after\", bundle.injectedTaskCount);\n\n const parts = [...bundle.parts, longRunningBlock].filter(Boolean);\n if (parts.length === 0) return undefined;\n\n const context = parts.join(\"\\n\\n\");\n const staleCount = activeForInjection.filter((t) => t.stale).length;\n const src = ctx.cfg.activeTask.ledger === \"facts\" ? \"category:project facts\" : \"ACTIVE-TASKS.md\";\n api.logger?.info?.(\n `memory-hybrid: active-task injection from ${src}: ledger=${bundle.ledgerActiveCount} filtered=${bundle.filteredActiveCount} injected=${bundle.injectedTaskCount} (~${bundle.injectedTokens} tok)${staleCount > 0 ? ` (${staleCount} stale in ledger)` : \"\"}`,\n );\n return { prependContext: `${context}\\n\\n` };\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-injection\",\n subsystem: \"active-task\",\n });\n api.logger?.warn?.(`memory-hybrid: active task injection failed: ${err}`);\n }\n });\n}\n"],"mappings":";;;;;;;;;;;;;AA+BA,SAAgB,4BACd,KACA,KACA,wBACA,eACM;CACN,IAAI,CAAC,IAAI,IAAI,WAAW,WAAW,IAAI,IAAI,cAAc,UAAU;CACnE,IAAI,oCAAoC;CAExC,IAAI,GAAG,sBAAsB,OAAO,OAAgB,YAAqB;EACvE,IAAI;GACF,MAAM,eAAe,cAAc,IAAI,IAAI,WAAW,eAAe;GACrE,IAAI,qBAA6E,EAAE;GACnF,IAAI,oBAA4E,EAAE;GAClF,MAAM,WAAW,2BAA2B,MAAM;GAClD,MAAM,kBAAkB,IAAI,IAAI,WAAW,YAAY,yBAAyB,QAAQ;GACxF,MAAM,WACJ,YAAY,oBAAoB,QAAQ,kCAAkC,UAAU,cAAc,GAAG;GAEvG,MAAM,aAAa,+BAA+B,OAD9B,sBAAsB,KAAK,QACqB,CAAC;GACrE,IAAI,wBACF;GACF,IAAI,wBAAuC;GAC3C,IAAI,wBAAwB;GAE5B,IAAI,IAAI,IAAI,WAAW,WAAW,SAAS;IACzC,wBAAwB,KAAK,KAAK;IAClC,MAAM,EAAE,QAAQ,YAAY,mCAAmC,IAAI,QAAQ;IAC3E,qBAAqB,iBAAiB,QAAQ,aAAa;IAC3D,wBAAwB;IACxB,wBAAwB,mBAAmB,QAAQ,SAAS,KAAK,MAAM,CAAC;UACnE;IACL,MAAM,WAAW,MAAM,mBAAmB,wBAAwB,aAAa;IAC/E,qBAAqB,UAAU,UAAU,EAAE;IAC3C,oBAAoB,UAAU,aAAa,EAAE;;GAG/C,MAAM,qBAAqB,kBAAgC;IACzD,IAAI,CAAC,yBAAyB,0BAA0B,MAAM;IAC9D,IAAI,QAAQ,QACV,oDAAoD,sBAAsB,mBAAmB,mBAAmB,sBAAsB,mBAAmB,uBAAuB,sBAAsB,uBAAuB,oBAAoB,sBAAsB,iBAAiB,gBAAgB,sBAAsB,YAAY,cAAc,aAAa,KAAK,KAAK,GAAG,wBACnX;;GAEH,MAAM,kCAAkC,OAAe,kBAAgC;IACrF,IAAI,mCAAmC;IACvC,oCAAoC;IACpC,8BAA8B;KAC5B,QAAQ,IAAI;KACZ,WAAW;KACX,WAAW;KACX;KACA,SAAS;KACT,MAAM;MACJ,QAAQ,IAAI,IAAI,WAAW;MAC3B,kBAAkB,mBAAmB;MACrC,iBAAiB;MACjB;MACD;KACF,CAAC;;GAGJ,IAAI,mBAAmB;GACvB,IAAI,UAAU;IACZ,MAAM,QAAQ,0BAA0B,SAAS;IACjD,MAAM,gBAAgB,mBAAmB,MAAM,MAAM,EAAE,MAAM,aAAa,KAAK,MAAM,MAAM,aAAa,CAAC;IACzG,IAAI,cAAc;IAElB,IAAI,CAAC,iBAAiB,kCAAkC,iBAAiB,WAAW,EAClF,IAAI,IAAI,IAAI,WAAW,WAAW,SAAS;KACzC,MAAM,2BAA2B,IAAI,SAAS,IAAI,UAAU,IAAI,YAAY,OAAO,IAAI,OAAO;KAC9F,qBAAqB,WAAW,oBAAoB,OAAO,KAAK;KAChE,cAAc;WACT;KACL,MAAM,UAAU,WAAW,oBAAoB,OAAO,KAAK;KAC3D,MAAM,cAAc,MAAM,2BACxB,wBACA,SACA,mBACA,cAAc,KAAA,EACf;KACD,IAAI,YAAY,SACd,IAAI,QAAQ,QAAQ,+DAA+D,YAAY,SAAS;UACnG;MACL,qBAAqB;MACrB,cAAc;;;IAKpB,mBAAmB,sCAAsC,UAAU,OAAO;KACxE,MAAM;KACN;KACA;KACA;KACD,CAAC;;GAGJ,IAAI,mBAAmB,WAAW,KAAK,CAAC,kBAAkB;IACxD,+BAA+B,8CAA8C,EAAE;IAC/E,kBAAkB,EAAE;IACpB;;GAGF,MAAM,KAAK,IAAI,IAAI,WAAW;GAC9B,MAAM,cACJ,GAAG,uBACH,IAAI,IAAI,gBAAgB,WACxB,CAAC,CAAC,YACF,iBAAiB,UAAU,IAAI,IAAI,gBAAgB;GAErD,IAAI,yBAAyB;GAC7B,IACE,eACA,mBAAmB,SAAS,KAC5B,IAAI,IAAI,gBAAgB,iBAAiB,2BAIzC,yBAAyB,kCAAkC,MADvC,UADH,gBAAgB,eAAe,IAAI,IAAI,gBAAgB,SAClC,CAAC,EAC2B,EAChE,UAAU,KAAK,IAAI,MAAM,GAAG,uBAAuB,EACpD,CAAC;GAGJ,MAAM,SAAS,6BAA6B;IAC1C,aAAa;IACb,uBAAuB,IAAI,IAAI,WAAW;IAC1C;IACA,qBAAqB,IAAI,IAAI,WAAW,aAAa;IACrD,YAAY,IAAI,IAAI,WAAW;IAC/B,mBAAmB,IAAI,IAAI,WAAW;IACtC,UAAU,YAAY,KAAA;IACtB,YAAY,cAAc,KAAA;IAC1B,kBACE,eAAe,mBAAmB,SAAS,IACvC;KACE,UAAU,GAAG;KACb,6BAA6B,GAAG;KACjC,GACD,KAAA;IACN,qBAAqB,0BAA0B,KAAA;IAChD,CAAC;GAEF,IAAI,eAAe,OAAO,MAAM,MAAM,MAAM,EAAE,SAAS,iBAAiB,CAAC,EACvE,IAAI,QAAQ,OAAO,+DAA+D;GAGpF,kBAAkB,OAAO,kBAAkB;GAC3C,+BAA+B,8CAA8C,OAAO,kBAAkB;GAEtG,MAAM,QAAQ,CAAC,GAAG,OAAO,OAAO,iBAAiB,CAAC,OAAO,QAAQ;GACjE,IAAI,MAAM,WAAW,GAAG,OAAO,KAAA;GAE/B,MAAM,UAAU,MAAM,KAAK,OAAO;GAClC,MAAM,aAAa,mBAAmB,QAAQ,MAAM,EAAE,MAAM,CAAC;GAC7D,MAAM,MAAM,IAAI,IAAI,WAAW,WAAW,UAAU,2BAA2B;GAC/E,IAAI,QAAQ,OACV,6CAA6C,IAAI,WAAW,OAAO,kBAAkB,YAAY,OAAO,oBAAoB,YAAY,OAAO,kBAAkB,KAAK,OAAO,eAAe,OAAO,aAAa,IAAI,KAAK,WAAW,qBAAqB,KAC1P;GACD,OAAO,EAAE,gBAAgB,GAAG,QAAQ,OAAO;WACpC,KAAK;GACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAAE;IACtE,WAAW;IACX,WAAW;IACZ,CAAC;GACF,IAAI,QAAQ,OAAO,gDAAgD,MAAM;;GAE3E"}
|
|
1
|
+
{"version":3,"file":"stage-active-task.js","names":[],"sources":["../../lifecycle/stage-active-task.ts"],"sourcesContent":["/**\n * Lifecycle: active-task injection (Phase 2.3).\n * Registers before_agent_start to inject ACTIVE-TASKS.md summary when enabled.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n detectStaleTasks,\n readActiveTaskFile,\n upsertTask,\n writeActiveTaskFileGuarded,\n} from \"../services/active-task.js\";\nimport { buildActiveTaskContextBundle } from \"../services/active-task-injection.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { listGoals, resolveGoalsDir } from \"../services/goal-registry.js\";\nimport { matchesHeartbeat } from \"../services/goal-stewardship-heartbeat.js\";\nimport {\n buildGoalEscalationHeartbeatBlock,\n buildLongRunningTaskDraft,\n buildLongRunningTaskRegistrationBlock,\n detectLongRunningWorkflowProposal,\n shouldAutoRegisterLongRunningTask,\n} from \"../services/task-hygiene.js\";\nimport { loadTaskLedgerFromFactsWithMetrics, syncActiveTaskEntryToFacts } from \"../services/task-ledger-facts.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport { extractLastUserMessageText } from \"../utils/extract-last-user-message.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { resolveSessionKeyFromHookEvent } from \"./session-state.js\";\nimport type { LifecycleContext } from \"./types.js\";\n\nexport function registerActiveTaskInjection(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n resolvedActiveTaskPath: string,\n workspaceRoot: string,\n): void {\n if (!ctx.cfg.activeTask.enabled || ctx.cfg.verbosity === \"silent\") return;\n let firstActiveTaskProjectionCaptured = false;\n\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n try {\n const staleMinutes = parseDuration(ctx.cfg.activeTask.staleThreshold);\n let activeForInjection: import(\"../services/active-task.js\").ActiveTaskEntry[] = [];\n let completedForWrite: import(\"../services/active-task.js\").ActiveTaskEntry[] = [];\n const userText = extractLastUserMessageText(event);\n const longRunningMode = ctx.cfg.activeTask.taskHygiene.longRunningRegistration?.mode ?? \"suggest\";\n const proposal =\n userText && longRunningMode !== \"off\" ? detectLongRunningWorkflowProposal(userText, workspaceRoot) : null;\n const resolvedApi = withHookResolutionApi(api, hookCtx);\n const sessionKey = resolveSessionKeyFromHookEvent(event, resolvedApi);\n let factsSelectionMetrics: import(\"../services/task-ledger-facts.js\").ActiveTaskLedgerSelectionMetrics | null =\n null;\n let factsSelectionStartMs: number | null = null;\n let staleSkippedFromFacts = 0;\n\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n factsSelectionStartMs = Date.now();\n const { active, metrics } = loadTaskLedgerFromFactsWithMetrics(ctx.factsDb);\n activeForInjection = detectStaleTasks(active, staleMinutes);\n factsSelectionMetrics = metrics;\n staleSkippedFromFacts = activeForInjection.filter((task) => task.stale).length;\n } else {\n const taskFile = await readActiveTaskFile(resolvedActiveTaskPath, staleMinutes);\n activeForInjection = taskFile?.active ?? [];\n completedForWrite = taskFile?.completed ?? [];\n }\n\n const logFactsSelection = (injectedCount: number): void => {\n if (!factsSelectionMetrics || factsSelectionStartMs === null) return;\n api.logger?.debug?.(\n `memory-hybrid: active-task selection rowsFetched=${factsSelectionMetrics.projectRowsFetched} groupedEntities=${factsSelectionMetrics.groupedEntityCount} duplicatesCollapsed=${factsSelectionMetrics.duplicateRowsCollapsed} activeCandidates=${factsSelectionMetrics.activeCandidates} staleSkipped=${staleSkippedFromFacts} injected=${injectedCount} elapsedMs=${Date.now() - factsSelectionStartMs}`,\n );\n };\n const logStartupProjectionCheckpoint = (phase: string, injectedCount: number): void => {\n if (firstActiveTaskProjectionCaptured) return;\n firstActiveTaskProjectionCaptured = true;\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"active-task\",\n operation: \"first-projection\",\n phase,\n onceKey: \"startup.first-active-task-projection\",\n tags: {\n ledger: ctx.cfg.activeTask.ledger,\n activeCandidates: activeForInjection.length,\n staleCandidates: staleSkippedFromFacts,\n injectedCount,\n },\n });\n };\n\n let longRunningBlock = \"\";\n if (proposal) {\n const draft = buildLongRunningTaskDraft(proposal);\n const alreadyActive = activeForInjection.some((t) => t.label.toLowerCase() === draft.label.toLowerCase());\n let autoCreated = false;\n\n if (!alreadyActive && shouldAutoRegisterLongRunningTask(longRunningMode, sessionKey)) {\n if (ctx.cfg.activeTask.ledger === \"facts\") {\n await syncActiveTaskEntryToFacts(ctx.factsDb, ctx.vectorDb, ctx.embeddings, draft, api.logger);\n activeForInjection = upsertTask(activeForInjection, draft, true);\n autoCreated = true;\n } else {\n const updated = upsertTask(activeForInjection, draft, true);\n const writeResult = await writeActiveTaskFileGuarded(\n resolvedActiveTaskPath,\n updated,\n completedForWrite,\n sessionKey ?? undefined,\n );\n if (writeResult.skipped) {\n api.logger?.debug?.(`memory-hybrid: skipped long-running task auto-registration: ${writeResult.reason}`);\n } else {\n activeForInjection = updated;\n autoCreated = true;\n }\n }\n }\n\n longRunningBlock = buildLongRunningTaskRegistrationBlock(proposal, draft, {\n mode: longRunningMode,\n autoCreated,\n alreadyActive,\n sessionKey,\n });\n }\n\n if (activeForInjection.length === 0 && !longRunningBlock) {\n logStartupProjectionCheckpoint(\"startup.first-active-task-projection.empty\", 0);\n logFactsSelection(0);\n return undefined;\n }\n\n const th = ctx.cfg.activeTask.taskHygiene;\n const isHeartbeat =\n th.heartbeatEscalation &&\n ctx.cfg.goalStewardship.enabled &&\n !!userText &&\n matchesHeartbeat(userText, ctx.cfg.goalStewardship);\n\n let goalEscalationPrebuilt = \"\";\n if (\n isHeartbeat &&\n activeForInjection.length > 0 &&\n ctx.cfg.goalStewardship.escalationPolicy.taskHygieneOnBlockedGoals\n ) {\n const goalsDir = resolveGoalsDir(workspaceRoot, ctx.cfg.goalStewardship.goalsDir);\n const goals = await listGoals(goalsDir);\n goalEscalationPrebuilt = buildGoalEscalationHeartbeatBlock(goals, {\n maxChars: Math.min(1200, th.heartbeatNudgeMaxChars),\n });\n }\n\n const bundle = buildActiveTaskContextBundle({\n ledgerTasks: activeForInjection,\n injectionBudgetTokens: ctx.cfg.activeTask.injectionBudget,\n staleMinutes,\n staleWarningEnabled: ctx.cfg.activeTask.staleWarning.enabled,\n projection: ctx.cfg.activeTask.projection,\n injectionMaxTasks: ctx.cfg.activeTask.injectionMaxTasks,\n userText: userText ?? undefined,\n sessionKey: sessionKey ?? undefined,\n heartbeatHygiene:\n isHeartbeat && activeForInjection.length > 0\n ? {\n maxChars: th.heartbeatNudgeMaxChars,\n suggestGoalAfterTaskAgeDays: th.suggestGoalAfterTaskAgeDays,\n }\n : undefined,\n goalEscalationBlock: goalEscalationPrebuilt || undefined,\n });\n\n if (isHeartbeat && bundle.parts.some((p) => p.includes(\"<task-hygiene>\"))) {\n api.logger?.info?.(\"memory-hybrid: task hygiene block appended (heartbeat match)\");\n }\n\n logFactsSelection(bundle.injectedTaskCount);\n logStartupProjectionCheckpoint(\"startup.first-active-task-projection.after\", bundle.injectedTaskCount);\n\n const parts = [...bundle.parts, longRunningBlock].filter(Boolean);\n if (parts.length === 0) return undefined;\n\n const context = parts.join(\"\\n\\n\");\n const staleCount = activeForInjection.filter((t) => t.stale).length;\n const src = ctx.cfg.activeTask.ledger === \"facts\" ? \"category:project facts\" : \"ACTIVE-TASKS.md\";\n api.logger?.info?.(\n `memory-hybrid: active-task injection from ${src}: ledger=${bundle.ledgerActiveCount} filtered=${bundle.filteredActiveCount} injected=${bundle.injectedTaskCount} (~${bundle.injectedTokens} tok)${staleCount > 0 ? ` (${staleCount} stale in ledger)` : \"\"}`,\n );\n return { prependContext: `${context}\\n\\n` };\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"active-task-injection\",\n subsystem: \"active-task\",\n });\n api.logger?.warn?.(`memory-hybrid: active task injection failed: ${err}`);\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-auth-failure.js","names":["msgObj"],"sources":["../../lifecycle/stage-auth-failure.ts"],"sourcesContent":["/**\n * Lifecycle: auth-failure recall (Phase 2.3).\n * On before_agent_start, detect auth failure in prompt/messages and inject credential facts.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n type AuthFailurePattern,\n DEFAULT_AUTH_FAILURE_PATTERNS,\n buildCredentialQuery,\n detectAuthFailure,\n formatCredentialHint,\n} from \"../services/auth-failure-detect.js\";\nimport { VAULT_POINTER_PREFIX } from \"../services/auto-capture.js\";\nimport { shouldSuppressEmbeddingError } from \"../services/embeddings.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { filterByScope, mergeResults } from \"../services/merge-results.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { isRecallContextSuperseded, suppressStaleLifecycleDbError } from \"../utils/registration-superseded.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nexport function registerAuthFailureRecall(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): void {\n if (!ctx.cfg.autoRecall.enabled || !ctx.cfg.autoRecall.authFailure.enabled) return;\n\n const customPatterns: AuthFailurePattern[] = [];\n for (const p of ctx.cfg.autoRecall.authFailure.patterns) {\n try {\n customPatterns.push({\n regex: new RegExp(p, \"i\"),\n type: \"generic\" as const,\n hint: p,\n });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auth-failure-regex\",\n subsystem: \"auto-recall\",\n });\n api.logger.warn?.(`memory-hybrid: invalid regex pattern \"${p}\": ${err}`);\n }\n }\n const allPatterns = [...DEFAULT_AUTH_FAILURE_PATTERNS, ...customPatterns];\n const { resolveSessionKey, authFailureRecallsThisSession } = sessionState;\n const currentAgentIdRef = ctx.currentAgentIdRef;\n\n // Two-arg hook: merge PluginHookAgentContext into api before resolveSessionKey (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const e = event as { prompt?: string; messages?: unknown[] };\n if (!e.prompt && (!e.messages || !Array.isArray(e.messages))) return;\n const sessionKey = resolveSessionKey(event, rApi) ?? currentAgentIdRef.value ?? \"default\";\n\n try {\n let textToScan = e.prompt || \"\";\n if (e.messages && Array.isArray(e.messages)) {\n const recentMessages = e.messages.slice(-5);\n for (const msg of recentMessages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") textToScan += `\\n${content}`;\n }\n }\n\n const detection = detectAuthFailure(textToScan, allPatterns);\n if (!detection.detected || !detection.target) return;\n\n const recallKey = `${sessionKey}:${detection.target}`;\n const recallCount = authFailureRecallsThisSession.get(recallKey) || 0;\n const maxRecalls = ctx.cfg.autoRecall.authFailure.maxRecallsPerTarget;\n if (maxRecalls > 0 && recallCount >= maxRecalls) {\n api.logger.debug?.(\n `memory-hybrid: auth failure for ${detection.target} already recalled ${recallCount} times this session, skipping`,\n );\n return;\n }\n\n const query = buildCredentialQuery(detection);\n if (!query) return;\n\n api.logger.info?.(\n `memory-hybrid: auth failure detected for ${detection.target} (${detection.hint}), searching for credentials...`,\n );\n\n const detectedAgentId = currentAgentIdRef.value || ctx.cfg.multiAgent.orchestratorId;\n const scopeFilter: ScopeFilter | undefined =\n detectedAgentId && detectedAgentId !== ctx.cfg.multiAgent.orchestratorId\n ? {\n userId: ctx.cfg.autoRecall.scopeFilter?.userId ?? null,\n agentId: detectedAgentId,\n sessionId: ctx.cfg.autoRecall.scopeFilter?.sessionId ?? null,\n }\n : undefined;\n\n const ftsResults = ctx.factsDb.search(query, 5, {\n scopeFilter,\n reinforcementBoost: ctx.cfg.distill?.reinforcementBoost ?? 0.1,\n diversityWeight: ctx.cfg.reinforcement?.diversityWeight ?? 1.0,\n interactiveFtsFastPath: true,\n });\n const vector = await ctx.embeddings.embed(query);\n let lanceResults = await ctx.vectorDb.search(vector, 5, 0.3);\n lanceResults = filterByScope(lanceResults, (id, opts) => ctx.factsDb.getById(id, opts), scopeFilter);\n\n const merged = mergeResults(\n ftsResults.map((r) => ({ ...r, backend: \"sqlite\" as const })),\n lanceResults.map((r) => ({ ...r, backend: \"lancedb\" as const })),\n 5,\n ctx.factsDb,\n );\n\n const scopeValidatedMerged = scopeFilter\n ? merged.filter((r) => ctx.factsDb.getById(r.entry.id, { scopeFilter }) != null)\n : merged;\n\n let credentialFacts = scopeValidatedMerged.filter((r) => {\n const fact = r.entry;\n if (fact.category === \"technical\") return true;\n if (fact.entity?.toLowerCase() === \"credentials\") return true;\n const tags = fact.tags || [];\n return tags.some((t) => [\"credential\", \"ssh\", \"token\", \"api\", \"auth\", \"password\"].includes(t.toLowerCase()));\n });\n\n if (!ctx.cfg.autoRecall.authFailure.includeVaultHints) {\n credentialFacts = credentialFacts.filter((r) => {\n const fact = r.entry;\n return (\n !fact.text.includes(\"stored in secure vault\") &&\n (!fact.value || !String(fact.value).startsWith(VAULT_POINTER_PREFIX))\n );\n });\n }\n\n credentialFacts = credentialFacts.slice(0, 3);\n\n if (credentialFacts.length === 0) {\n api.logger.info?.(`memory-hybrid: no credential facts found for ${detection.target}`);\n return;\n }\n\n const hint = formatCredentialHint(\n detection,\n credentialFacts.map((r) => r.entry),\n );\n if (hint) {\n api.logger.info?.(\n `memory-hybrid: injecting ${credentialFacts.length} credential facts for ${detection.target}`,\n );\n authFailureRecallsThisSession.set(recallKey, recallCount + 1);\n return { prependContext: `${hint}\\n\\n` };\n }\n } catch (err) {\n if (isRecallContextSuperseded(ctx)) {\n api.logger.debug?.(\"memory-hybrid: auth failure recall skipped (registration superseded)\");\n return;\n }\n if (\n suppressStaleLifecycleDbError(\n ctx,\n err,\n api.logger,\n \"memory-hybrid: auth failure recall skipped (registration superseded)\",\n )\n ) {\n return;\n }\n if (!shouldSuppressEmbeddingError(err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auth-failure-recall\",\n subsystem: \"auto-recall\",\n });\n }\n api.logger.warn(`memory-hybrid: auth failure recall failed: ${String(err)}`);\n }\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stage-auth-failure.js","names":["msgObj"],"sources":["../../lifecycle/stage-auth-failure.ts"],"sourcesContent":["/**\n * Lifecycle: auth-failure recall (Phase 2.3).\n * On before_agent_start, detect auth failure in prompt/messages and inject credential facts.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport {\n type AuthFailurePattern,\n DEFAULT_AUTH_FAILURE_PATTERNS,\n buildCredentialQuery,\n detectAuthFailure,\n formatCredentialHint,\n} from \"../services/auth-failure-detect.js\";\nimport { VAULT_POINTER_PREFIX } from \"../services/auto-capture.js\";\nimport { shouldSuppressEmbeddingError } from \"../services/embeddings.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { filterByScope, mergeResults } from \"../services/merge-results.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { withHookResolutionApi } from \"./hook-resolution-api.js\";\nimport { isRecallContextSuperseded, suppressStaleLifecycleDbError } from \"../utils/registration-superseded.js\";\nimport type { LifecycleContext, SessionState } from \"./types.js\";\n\nexport function registerAuthFailureRecall(\n api: ClawdbotPluginApi,\n ctx: LifecycleContext,\n sessionState: SessionState,\n): void {\n if (!ctx.cfg.autoRecall.enabled || !ctx.cfg.autoRecall.authFailure.enabled) return;\n\n const customPatterns: AuthFailurePattern[] = [];\n for (const p of ctx.cfg.autoRecall.authFailure.patterns) {\n try {\n customPatterns.push({\n regex: new RegExp(p, \"i\"),\n type: \"generic\" as const,\n hint: p,\n });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auth-failure-regex\",\n subsystem: \"auto-recall\",\n });\n api.logger.warn?.(`memory-hybrid: invalid regex pattern \"${p}\": ${err}`);\n }\n }\n const allPatterns = [...DEFAULT_AUTH_FAILURE_PATTERNS, ...customPatterns];\n const { resolveSessionKey, authFailureRecallsThisSession } = sessionState;\n const currentAgentIdRef = ctx.currentAgentIdRef;\n\n // Two-arg hook: merge PluginHookAgentContext into api before resolveSessionKey (#1005).\n api.on(\"before_agent_start\", async (event: unknown, hookCtx: unknown) => {\n const rApi = withHookResolutionApi(api, hookCtx);\n const e = event as { prompt?: string; messages?: unknown[] };\n if (!e.prompt && (!e.messages || !Array.isArray(e.messages))) return;\n const sessionKey = resolveSessionKey(event, rApi) ?? currentAgentIdRef.value ?? \"default\";\n\n try {\n let textToScan = e.prompt || \"\";\n if (e.messages && Array.isArray(e.messages)) {\n const recentMessages = e.messages.slice(-5);\n for (const msg of recentMessages) {\n if (!msg || typeof msg !== \"object\") continue;\n const msgObj = msg as Record<string, unknown>;\n const content = msgObj.content;\n if (typeof content === \"string\") textToScan += `\\n${content}`;\n }\n }\n\n const detection = detectAuthFailure(textToScan, allPatterns);\n if (!detection.detected || !detection.target) return;\n\n const recallKey = `${sessionKey}:${detection.target}`;\n const recallCount = authFailureRecallsThisSession.get(recallKey) || 0;\n const maxRecalls = ctx.cfg.autoRecall.authFailure.maxRecallsPerTarget;\n if (maxRecalls > 0 && recallCount >= maxRecalls) {\n api.logger.debug?.(\n `memory-hybrid: auth failure for ${detection.target} already recalled ${recallCount} times this session, skipping`,\n );\n return;\n }\n\n const query = buildCredentialQuery(detection);\n if (!query) return;\n\n api.logger.info?.(\n `memory-hybrid: auth failure detected for ${detection.target} (${detection.hint}), searching for credentials...`,\n );\n\n const detectedAgentId = currentAgentIdRef.value || ctx.cfg.multiAgent.orchestratorId;\n const scopeFilter: ScopeFilter | undefined =\n detectedAgentId && detectedAgentId !== ctx.cfg.multiAgent.orchestratorId\n ? {\n userId: ctx.cfg.autoRecall.scopeFilter?.userId ?? null,\n agentId: detectedAgentId,\n sessionId: ctx.cfg.autoRecall.scopeFilter?.sessionId ?? null,\n }\n : undefined;\n\n const ftsResults = ctx.factsDb.search(query, 5, {\n scopeFilter,\n reinforcementBoost: ctx.cfg.distill?.reinforcementBoost ?? 0.1,\n diversityWeight: ctx.cfg.reinforcement?.diversityWeight ?? 1.0,\n interactiveFtsFastPath: true,\n });\n const vector = await ctx.embeddings.embed(query);\n let lanceResults = await ctx.vectorDb.search(vector, 5, 0.3);\n lanceResults = filterByScope(lanceResults, (id, opts) => ctx.factsDb.getById(id, opts), scopeFilter);\n\n const merged = mergeResults(\n ftsResults.map((r) => ({ ...r, backend: \"sqlite\" as const })),\n lanceResults.map((r) => ({ ...r, backend: \"lancedb\" as const })),\n 5,\n ctx.factsDb,\n );\n\n const scopeValidatedMerged = scopeFilter\n ? merged.filter((r) => ctx.factsDb.getById(r.entry.id, { scopeFilter }) != null)\n : merged;\n\n let credentialFacts = scopeValidatedMerged.filter((r) => {\n const fact = r.entry;\n if (fact.category === \"technical\") return true;\n if (fact.entity?.toLowerCase() === \"credentials\") return true;\n const tags = fact.tags || [];\n return tags.some((t) => [\"credential\", \"ssh\", \"token\", \"api\", \"auth\", \"password\"].includes(t.toLowerCase()));\n });\n\n if (!ctx.cfg.autoRecall.authFailure.includeVaultHints) {\n credentialFacts = credentialFacts.filter((r) => {\n const fact = r.entry;\n return (\n !fact.text.includes(\"stored in secure vault\") &&\n (!fact.value || !String(fact.value).startsWith(VAULT_POINTER_PREFIX))\n );\n });\n }\n\n credentialFacts = credentialFacts.slice(0, 3);\n\n if (credentialFacts.length === 0) {\n api.logger.info?.(`memory-hybrid: no credential facts found for ${detection.target}`);\n return;\n }\n\n const hint = formatCredentialHint(\n detection,\n credentialFacts.map((r) => r.entry),\n );\n if (hint) {\n api.logger.info?.(\n `memory-hybrid: injecting ${credentialFacts.length} credential facts for ${detection.target}`,\n );\n authFailureRecallsThisSession.set(recallKey, recallCount + 1);\n return { prependContext: `${hint}\\n\\n` };\n }\n } catch (err) {\n if (isRecallContextSuperseded(ctx)) {\n api.logger.debug?.(\"memory-hybrid: auth failure recall skipped (registration superseded)\");\n return;\n }\n if (\n suppressStaleLifecycleDbError(\n ctx,\n err,\n api.logger,\n \"memory-hybrid: auth failure recall skipped (registration superseded)\",\n )\n ) {\n return;\n }\n if (!shouldSuppressEmbeddingError(err)) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n operation: \"auth-failure-recall\",\n subsystem: \"auto-recall\",\n });\n }\n api.logger.warn(`memory-hybrid: auth failure recall failed: ${String(err)}`);\n }\n });\n}\n"],"mappings":"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"}
|