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":"provider-router.js","names":[],"sources":["../../setup/provider-router.ts"],"sourcesContent":["/** @module provider-router — Multi-provider LLM routing (OpenAI-compatible) and API key resolution. */\nimport OpenAI from \"openai\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { CostTracker } from \"../backends/cost-tracker.js\";\nimport type { HybridMemoryConfig, LLMProviderConfig, ResolvedGatewayAuthConfig } from \"../config.js\";\nimport {\n EMBEDDING_DIMENSIONS,\n OPENAI_MODELS,\n normalizeResolvedSecretValue,\n resolveSecretRef,\n} from \"../config/parsers/core.js\";\nimport { UnconfiguredProviderError } from \"../services/chat.js\";\nimport { isAzureOpenAiResourceEndpoint } from \"../services/embeddings/shared.js\";\nimport {\n requiresMaxCompletionTokens,\n resolveWireApi,\n shouldOmitSamplingParams,\n} from \"../services/model-capabilities.js\";\nimport {\n type ResponsesApiResponse,\n buildResponsesRequestFromChatBody,\n responsesRawToChatCompletion,\n} from \"../services/responses-adapter.js\";\nimport { createApimGatewayFetch, isAzureApiManagementGatewayUrl } from \"../utils/apim-gateway-fetch.js\";\nimport {\n DEFAULT_BACKOFF_MINUTES,\n DEFAULT_RESET_AFTER_HOURS,\n isOAuthInBackoff,\n recordOAuthFailure,\n} from \"../utils/auth-failover.js\";\nimport { hasOAuthProfiles } from \"../utils/auth.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { inferFeatureLabel } from \"./cost-instrumentation.js\";\n\n/** Minimal logger shape accepted by the log-once helpers. */\ninterface InfoLogger {\n logger?: { info?: (msg: string) => void };\n}\n\n/**\n * Process-lifetime set of log keys that have already been emitted.\n * Prevents the same gateway-provider info message from flooding logs when the plugin\n * initialises multiple times in the same process (e.g. once per CLI invocation in a step).\n * Reset via resetGatewayLogOnceForTesting() in unit tests for isolation.\n */\nconst _loggedOnceKeys = new Set<string>();\n\n/**\n * Emit `msg` via `api.logger.info` at most once per process for the given `key`.\n * Subsequent calls with the same key are silently dropped.\n */\nfunction logInfoOnce(key: string, msg: string, api: InfoLogger): void {\n if (_loggedOnceKeys.has(key)) return;\n _loggedOnceKeys.add(key);\n api.logger?.info?.(msg);\n}\n\n/**\n * Reset the log-once guard. Call this in tests to ensure each test starts clean.\n */\nexport function resetGatewayLogOnceForTesting(): void {\n _loggedOnceKeys.clear();\n}\n\n/**\n * Public wrapper around logInfoOnce for use outside this module (e.g. bootstrap-databases).\n * Emits `msg` via `api.logger.info` at most once per process for the given `key`.\n */\nexport function gatewayLogInfoOnce(key: string, msg: string, api: InfoLogger): void {\n logInfoOnce(key, msg, api);\n}\n\n/**\n * Normalize baseURL vs baseUrl (OpenClaw config uses camelCase `baseUrl`; SDK uses `baseURL`).\n * Intentionally duplicated from config/parsers/index.ts to avoid a circular module dependency —\n * init-databases bootstraps before the full config parser is available.\n */\nexport function readProviderBaseUrl(p: { baseURL?: string; baseUrl?: string } | undefined): string | undefined {\n if (!p) return undefined;\n const u = typeof p.baseURL === \"string\" ? p.baseURL : typeof p.baseUrl === \"string\" ? p.baseUrl : undefined;\n const t = u?.trim();\n return t && t.length > 0 ? t : undefined;\n}\n\n/**\n * Embeddings are created before `models.providers` is merged into `cfg.llm`. If `embedding.endpoint`\n * was stripped by the host validator or omitted, inherit the APIM / Foundry base from the global\n * `models.providers[\"azure-foundry\"]` entry so requests do not fall through to api.openai.com with\n * an Azure or subscription key (401 \"Incorrect API key\" from platform.openai.com).\n */\n/** OpenClaw gateway `models.providers` (or legacy `llm.providers` / top-level `providers`). */\nexport function getGatewayModelsProviders(\n gwConfig: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!gwConfig) return undefined;\n const p =\n (gwConfig.models as Record<string, unknown> | undefined)?.providers ??\n (gwConfig.llm as Record<string, unknown> | undefined)?.providers ??\n gwConfig.providers;\n if (!p || typeof p !== \"object\" || Array.isArray(p)) return undefined;\n return p as Record<string, unknown>;\n}\n\nexport function patchEmbeddingEndpointFromGatewayProviders(cfg: HybridMemoryConfig, api: ClawdbotPluginApi): void {\n const ep = cfg.embedding?.endpoint;\n if (typeof ep === \"string\" && ep.trim().length > 0) return;\n // Only inherit Azure Foundry endpoint for OpenAI provider\n if (cfg.embedding?.provider !== \"openai\") return;\n const gwConfig = api.config as Record<string, unknown> | undefined;\n const gwProviders = getGatewayModelsProviders(gwConfig);\n const af = gwProviders?.[\"azure-foundry\"] as { baseURL?: string; baseUrl?: string } | undefined;\n const base = readProviderBaseUrl(af);\n if (!base) return;\n (cfg.embedding as Record<string, unknown>).endpoint = base;\n api.logger?.info?.(\n `memory-hybrid: embedding.endpoint was empty — using models.providers[\"azure-foundry\"] base URL (${base})`,\n );\n}\n\n/** Existing `llm.providers` key whose name matches `normalizedName` case-insensitively (issue #1002 / PR #1003). */\nfunction findLlmProviderSlotKey(\n prov: Record<string, Record<string, unknown>>,\n normalizedName: string,\n): string | undefined {\n for (const k of Object.keys(prov)) {\n if (k.toLowerCase() === normalizedName) return k;\n }\n return undefined;\n}\n\nfunction llmProviderEntryAsPlainObject(raw: unknown): Record<string, unknown> {\n if (raw && typeof raw === \"object\" && !Array.isArray(raw)) return { ...(raw as Record<string, unknown>) };\n return {};\n}\n\n/**\n * Merge gateway `models.providers` apiKey/baseURL into plugin `llm.providers` (issues #487, #386).\n * Optionally records merged provider names for bootstrap tier-list augmentation.\n * Resolves mixed-case plugin keys (e.g. `OpenAI`) so gateway merge does not add a duplicate lowercase entry.\n */\nexport function mergeGatewayProviderCredentialsIntoLlmProvidersMap(\n prov: Record<string, Record<string, unknown>>,\n gwProviders: Record<string, unknown> | undefined,\n api: Pick<ClawdbotPluginApi, \"logger\">,\n mergedNames?: string[],\n mergedOriginals?: Map<string, string>,\n): number {\n let newApiKeySlots = 0;\n if (!gwProviders || typeof gwProviders !== \"object\" || Array.isArray(gwProviders)) return 0;\n for (const [name, gw] of Object.entries(gwProviders)) {\n if (!name || !gw || typeof gw !== \"object\") continue;\n const rawKey = (gw as Record<string, unknown>).apiKey ?? (gw as Record<string, unknown>).api_key;\n if (typeof rawKey !== \"string\" || !rawKey.trim()) continue;\n const normalizedName = name.toLowerCase();\n const slotKey = findLlmProviderSlotKey(prov, normalizedName);\n const targetKey = slotKey ?? normalizedName;\n const cur = llmProviderEntryAsPlainObject(prov[targetKey]);\n const pluginHasKey = typeof cur.apiKey === \"string\" && (cur.apiKey as string).trim().length > 0;\n if (!pluginHasKey) {\n newApiKeySlots++;\n prov[targetKey] = {\n ...cur,\n apiKey: rawKey.trim(),\n baseURL:\n (typeof cur.baseURL === \"string\" && cur.baseURL.trim() ? cur.baseURL : undefined) ??\n (gw as Record<string, unknown>).baseURL ??\n (gw as Record<string, unknown>).base_url ??\n (gw as Record<string, unknown>).baseUrl,\n };\n mergedNames?.push(normalizedName);\n mergedOriginals?.set(normalizedName, name);\n logInfoOnce(\n `gateway-provider:${normalizedName}`,\n `memory-hybrid: using gateway provider \"${name}\" for llm.providers (add ${normalizedName}/<model> to llm.default or llm.heavy to use)`,\n api,\n );\n } else {\n const gwBase =\n (gw as Record<string, unknown>).baseURL ??\n (gw as Record<string, unknown>).base_url ??\n (gw as Record<string, unknown>).baseUrl;\n const existingBase = typeof cur.baseURL === \"string\" && cur.baseURL.trim() ? cur.baseURL : undefined;\n if (typeof gwBase === \"string\" && gwBase.trim() && !existingBase) {\n prov[targetKey] = { ...cur, baseURL: gwBase.trim() };\n }\n mergedNames?.push(normalizedName);\n mergedOriginals?.set(normalizedName, name);\n }\n }\n return newApiKeySlots;\n}\n\nfunction stripEmbeddingModelPrefix(model: string): string {\n const t = model.trim();\n const slash = t.indexOf(\"/\");\n if (slash > 0 && slash < t.length - 1) return t.slice(slash + 1).trim();\n return t;\n}\n\nfunction mapMemorySearchProviderToEmbeddingProvider(providerRaw: string): \"openai\" | \"google\" | \"ollama\" | null {\n const x = providerRaw.trim().toLowerCase().replace(/_/g, \"-\");\n if (x === \"openai\" || x === \"azure-foundry\" || x === \"azure\" || x === \"azureopenai\" || x === \"azure-openai\")\n return \"openai\";\n if (x === \"google\" || x === \"gemini\" || x === \"vertex\") return \"google\";\n if (x === \"ollama\") return \"ollama\";\n return null;\n}\n\nfunction inferEmbeddingProviderFromBareModel(modelBare: string): \"openai\" | \"google\" | \"ollama\" | null {\n if (OPENAI_MODELS.has(modelBare)) return \"openai\";\n const m = modelBare.toLowerCase();\n if (m.includes(\"gemini\") && m.includes(\"embed\")) return \"google\";\n if (\n m.includes(\"nomic-embed\") ||\n m.includes(\"mxbai-embed\") ||\n m === \"all-minilm\" ||\n m.includes(\"snowflake-arctic-embed\")\n )\n return \"ollama\";\n if (m.startsWith(\"text-embedding\") || m.startsWith(\"embedding-\")) return \"openai\";\n return null;\n}\n\nfunction findGatewayProviderEntryLoose(\n gwProviders: Record<string, unknown>,\n providerHint: string,\n): Record<string, unknown> | undefined {\n const hint = providerHint.trim().toLowerCase().replace(/_/g, \"-\");\n for (const [k, v] of Object.entries(gwProviders)) {\n if (!v || typeof v !== \"object\" || Array.isArray(v)) continue;\n if (k.toLowerCase().replace(/_/g, \"-\") === hint) return v as Record<string, unknown>;\n }\n return undefined;\n}\n\n/**\n * Shallow-clone plugin config branches that global inheritance mutates (issue #1002).\n */\nexport function shallowClonePluginConfigForGatewayMerge(raw: Record<string, unknown>): Record<string, unknown> {\n const out = { ...raw };\n if (out.embedding && typeof out.embedding === \"object\" && !Array.isArray(out.embedding)) {\n out.embedding = { ...(out.embedding as Record<string, unknown>) };\n }\n if (out.llm && typeof out.llm === \"object\" && !Array.isArray(out.llm)) {\n const llm = { ...(out.llm as Record<string, unknown>) };\n if (llm.providers && typeof llm.providers === \"object\" && !Array.isArray(llm.providers)) {\n const p = { ...(llm.providers as Record<string, unknown>) };\n for (const key of Object.keys(p)) {\n const v = p[key];\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n p[key] = { ...(v as Record<string, unknown>) };\n }\n }\n llm.providers = p;\n }\n out.llm = llm;\n }\n return out;\n}\n\n/**\n * Before `hybridConfigSchema.parse`: merge gateway credentials into raw `llm.providers`, then\n * overlay `agents.defaults.memorySearch` onto `embedding` for omitted fields (issue #1002).\n * Plugin `embedding` / `llm.providers` entries always win when already set.\n */\nexport function applyGatewayEmbeddingInheritanceBeforeParse(\n raw: Record<string, unknown>,\n api: ClawdbotPluginApi,\n): void {\n const gw = api.config as Record<string, unknown> | undefined;\n const gwProviders = getGatewayModelsProviders(gw);\n if (gwProviders) {\n if (!raw.llm || typeof raw.llm !== \"object\" || Array.isArray(raw.llm)) {\n raw.llm = { providers: {} };\n } else {\n const plm0 = raw.llm as Record<string, unknown>;\n if (!plm0.providers || typeof plm0.providers !== \"object\" || Array.isArray(plm0.providers)) {\n plm0.providers = {};\n }\n }\n const plm = raw.llm as Record<string, unknown>;\n const prov = plm.providers as Record<string, Record<string, unknown>>;\n const n = mergeGatewayProviderCredentialsIntoLlmProvidersMap(prov, gwProviders, api);\n if (n > 0) {\n logInfoOnce(\n \"merged-gateway-providers\",\n `memory-hybrid: merged ${n} gateway provider credential(s) into plugin llm.providers before config parse (issue #1002)`,\n api,\n );\n }\n }\n\n const agents = gw?.agents as Record<string, unknown> | undefined;\n const defaults = agents?.defaults as Record<string, unknown> | undefined;\n const ms = defaults?.memorySearch as Record<string, unknown> | undefined;\n if (!ms || ms.enabled === false) return;\n\n const msProvider = typeof ms.provider === \"string\" ? ms.provider.trim() : \"\";\n const msModel = typeof ms.model === \"string\" ? ms.model.trim() : \"\";\n if (!msProvider && !msModel) return;\n\n let emb: Record<string, unknown>;\n if (!raw.embedding || typeof raw.embedding !== \"object\" || Array.isArray(raw.embedding)) {\n emb = {};\n raw.embedding = emb;\n } else {\n emb = { ...(raw.embedding as Record<string, unknown>) };\n raw.embedding = emb;\n }\n\n const modelBare = msModel ? stripEmbeddingModelPrefix(msModel) : \"\";\n let touched = false;\n\n if (msModel && emb.model === undefined) {\n emb.model = modelBare;\n touched = true;\n }\n\n let mapped = msProvider ? mapMemorySearchProviderToEmbeddingProvider(msProvider) : null;\n if (!mapped && modelBare) mapped = inferEmbeddingProviderFromBareModel(modelBare);\n if (mapped && emb.provider === undefined) {\n emb.provider = mapped;\n touched = true;\n }\n\n if (modelBare && emb.dimensions === undefined) {\n const d = EMBEDDING_DIMENSIONS[modelBare];\n if (typeof d === \"number\") {\n emb.dimensions = d;\n touched = true;\n }\n }\n\n if (gwProviders && msProvider && emb.deployment === undefined) {\n const gwp = findGatewayProviderEntryLoose(gwProviders, msProvider);\n if (gwp) {\n const dep =\n (typeof gwp.deployment === \"string\" && gwp.deployment.trim()) ||\n (typeof gwp.deploymentName === \"string\" && gwp.deploymentName.trim()) ||\n (typeof (gwp as { deploymentId?: string }).deploymentId === \"string\" &&\n (gwp as { deploymentId: string }).deploymentId.trim());\n if (dep) {\n emb.deployment = dep;\n touched = true;\n }\n }\n }\n\n const inheritedProvId = typeof emb.provider === \"string\" ? emb.provider.trim() : \"\";\n if (inheritedProvId && emb.apiKey === undefined) {\n const plmMerged = raw.llm && typeof raw.llm === \"object\" && !Array.isArray(raw.llm) ? raw.llm : null;\n const provMerged =\n plmMerged &&\n typeof (plmMerged as Record<string, unknown>).providers === \"object\" &&\n !Array.isArray((plmMerged as Record<string, unknown>).providers)\n ? ((plmMerged as Record<string, unknown>).providers as Record<string, unknown>)\n : {};\n const slot = findGatewayProviderEntryLoose(provMerged, inheritedProvId);\n const ak = slot && typeof slot.apiKey === \"string\" ? slot.apiKey.trim() : \"\";\n if (ak) {\n emb.apiKey = ak;\n touched = true;\n }\n }\n\n if (touched) {\n api.logger?.info?.(\n \"memory-hybrid: inherited embedding fields from agents.defaults.memorySearch (issue #1002); plugin embedding.* still overrides when set\",\n );\n }\n}\n\n/**\n * Provider prefixes that resolveClient() handles natively without explicit llm.providers config.\n * Keep in sync with the built-in provider cases in resolveClient() in this file.\n * If resolveClient() adds a new built-in provider, add it here too.\n */\nexport const ROUTABLE_BUILTIN_PROVIDERS = new Set([\"google\", \"openai\", \"anthropic\", \"ollama\", \"openrouter\", \"minimax\"]);\n\n/**\n * Extract gateway configuration from environment and plugin config.\n * Centralized to avoid duplicating this logic across buildMultiProviderOpenAI and initializeDatabases.\n */\nexport function extractGatewayConfig(cfg: HybridMemoryConfig): {\n gatewayPortRaw: string | undefined;\n gatewayPort: number | undefined;\n gatewayAuthResolved: string | undefined;\n gatewayToken: string | undefined;\n gatewayBaseUrl: string | undefined;\n} {\n const gatewayPortRaw = normalizeResolvedSecretValue(getEnv(\"OPENCLAW_GATEWAY_PORT\"));\n const gatewayPort = gatewayPortRaw ? Number.parseInt(gatewayPortRaw, 10) : undefined;\n const gatewayAuthResolved = (cfg.gateway?.auth as ResolvedGatewayAuthConfig | undefined)?._resolvedToken;\n const gatewayToken = gatewayAuthResolved ?? normalizeResolvedSecretValue(getEnv(\"OPENCLAW_GATEWAY_TOKEN\"));\n const gatewayBaseUrl =\n gatewayPort && gatewayPort >= 1 && gatewayPort <= 65535 ? `http://127.0.0.1:${gatewayPort}/v1` : undefined;\n return {\n gatewayPortRaw,\n gatewayPort,\n gatewayAuthResolved,\n gatewayToken,\n gatewayBaseUrl,\n };\n}\n\n/** Known provider OpenAI-compatible base URLs. */\nconst GOOGLE_GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\";\n/** Default Ollama server base URL (without /v1 path). */\nexport const OLLAMA_DEFAULT_BASE_URL = \"http://127.0.0.1:11434\";\n/** How long to cache an Ollama health-check result (positive or negative). */\nconst OLLAMA_HEALTH_CACHE_TTL_MS = 30_000;\n/** Timeout for a single Ollama /api/tags health ping. */\nexport const OLLAMA_HEALTH_TIMEOUT_MS = 2_000;\n\n/**\n * Module-level health cache so repeated calls within the TTL window skip the network round-trip.\n * Shared across plugin reloads in the same process (intentional).\n */\nconst _ollamaHealthCache = new Map<string, { ok: boolean; ts: number }>();\n\n/**\n * Probe an Ollama server via GET /api/tags (the Ollama health endpoint).\n * Returns true when Ollama is reachable and responsive, false otherwise.\n * Results are cached for OLLAMA_HEALTH_CACHE_TTL_MS to avoid hammering the endpoint.\n */\nexport async function probeOllamaEndpoint(baseUrl: string): Promise<boolean> {\n const now = Date.now();\n const cached = _ollamaHealthCache.get(baseUrl);\n if (cached && now - cached.ts < OLLAMA_HEALTH_CACHE_TTL_MS) return cached.ok;\n try {\n const resp = await fetch(`${baseUrl}/api/tags`, {\n signal: AbortSignal.timeout(OLLAMA_HEALTH_TIMEOUT_MS),\n });\n const ok = resp.ok;\n _ollamaHealthCache.set(baseUrl, { ok, ts: now });\n return ok;\n } catch {\n _ollamaHealthCache.set(baseUrl, { ok: false, ts: now });\n return false;\n }\n}\n\n/** Invalidate cached Ollama health result (e.g. after auto-start). */\nexport function clearOllamaHealthCacheEntry(baseUrl: string): void {\n _ollamaHealthCache.delete(baseUrl);\n}\n\nconst ANTHROPIC_BASE_URL = \"https://api.anthropic.com/v1\";\nconst ANTHROPIC_VERSION_HEADER = \"2023-06-01\";\n\n/** Built-in OpenAI-compatible base URL for MiniMax API (global endpoint). */\nexport const MINIMAX_BASE_URL = \"https://api.minimax.io/v1\";\n\n/**\n * Canonical MiniMax model name mapping (lowercase key → proper-case value).\n * Covers Ollama-style aliases (e.g. \"minimax-m2.5:cloud\") that users may configure\n * and that would otherwise produce a 404 from the MiniMax API (issue #400).\n */\nconst MINIMAX_MODEL_ALIASES: Record<string, string> = {\n \"minimax-m2.5\": \"MiniMax-M2.5\",\n \"minimax-text-01\": \"MiniMax-Text-01\",\n};\n\n/**\n * Canonicalize a bare MiniMax model name.\n * - Strips Ollama-style `:tag` suffixes (e.g. `:cloud`, `:latest`) which are invalid on the MiniMax API.\n * - Looks up the result in MINIMAX_MODEL_ALIASES to restore correct casing (e.g. \"minimax-m2.5\" → \"MiniMax-M2.5\").\n * - Falls back to the original bare name (without tag) if no alias matches.\n */\nfunction canonicalizeMiniMaxModelId(bare: string): string {\n // Strip Ollama-style \":tag\" suffix (e.g. \"minimax-m2.5:cloud\" → \"minimax-m2.5\")\n const withoutTag = bare.includes(\":\") ? bare.slice(0, bare.indexOf(\":\")) : bare;\n const canonical = MINIMAX_MODEL_ALIASES[withoutTag.toLowerCase()];\n return canonical ?? withoutTag;\n}\n\n/** OpenRouter OpenAI-compatible base URL. */\nexport const OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\n\n/** Resolved API key with metadata about which configuration source provided it. */\ntype ResolvedApiKey = { value?: string; source: string };\n\n/**\n * Centralised API-key resolver for all built-in and custom providers.\n *\n * Resolves the API key for a named provider using a well-defined precedence chain.\n * Provider-specific exceptions are explicit and documented here, rather than scattered\n * across individual provider branches in `resolveClient`.\n *\n * Precedence table (highest → lowest):\n *\n * | Source | google | openai | anthropic | openrouter | minimax | ollama | custom |\n * |-----------------------------|:------:|:------:|:---------:|:----------:|:-------:|:------:|:------:|\n * | llm.providers.X.apiKey | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n * | distill.apiKey (legacy) | ✓ | | | | | | |\n * | gatewayToken | | ✓† | | | | | |\n * | embedding.apiKey | | ✓† | | | | | |\n * | GOOGLE_API_KEY env | ✓ | | | | | | |\n * | OPENAI_API_KEY env | | ✓* | | | | | |\n * | AZURE_OPENAI_API_KEY env | | | | | | | ✓‡ |\n * | ANTHROPIC_API_KEY env | | | ✓ | | | | |\n * | OPENROUTER_API_KEY env | | | | ✓ | | | |\n * | MINIMAX_API_KEY env | | | | | ✓ | | |\n * | <PREFIX>_API_KEY env | | | | | | | ✓ |\n * | \"ollama\" (no-op default) | | | | | | ✓ | |\n *\n * * openai: OPENAI_API_KEY is preferred over embedding.apiKey so Azure and OpenAI keys do not conflict.\n * † openai: `gatewayToken` and `embedding.apiKey` are skipped when `hasCustomExternalBaseURL` is true\n * (security: never send internal gateway credentials to external endpoints).\n * ‡ azure-foundry / azure-foundry-responses: AZURE_OPENAI_API_KEY env when llm.providers.*.apiKey not set.\n *\n * @param prefix Lowercase provider prefix, e.g. \"google\", \"openai\".\n * @param providerCfg The llm.providers[prefix] config object, if present.\n * @param cfg Full plugin config.\n * @param resolveKey SecretRef resolver (env:VAR / file:// / ${VAR}).\n * @param opts.gatewayToken Resolved gateway auth token (openai only).\n * @param opts.hasCustomExternalBaseURL True when openai uses a non-gateway baseURL.\n * @param opts.env Process environment (injectable for tests; defaults to process.env).\n */\nexport function resolveProviderApiKey(\n prefix: string,\n providerCfg: LLMProviderConfig | undefined,\n cfg: HybridMemoryConfig,\n resolveKey: (key: string | undefined) => string | undefined,\n opts: {\n gatewayToken?: string;\n hasCustomExternalBaseURL?: boolean;\n env?: NodeJS.ProcessEnv;\n } = {},\n): ResolvedApiKey {\n const { gatewayToken, hasCustomExternalBaseURL = false, env = process.env } = opts;\n const readEnvKey = (name: string): string | undefined => normalizeResolvedSecretValue(env[name]);\n\n // Highest priority: explicit per-provider key in llm.providers config (all providers).\n const fromProviderCfg = resolveKey(providerCfg?.apiKey);\n if (fromProviderCfg) return { value: fromProviderCfg, source: `llm.providers.${prefix}.apiKey` };\n\n if (prefix === \"google\") {\n // Legacy fallback: distill.apiKey doubles as the Google API key for distillation.\n const fromDistill = resolveKey(cfg.distill?.apiKey);\n if (fromDistill) return { value: fromDistill, source: \"distill.apiKey\" };\n const fromEnv = readEnvKey(\"GOOGLE_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"GOOGLE_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"openai\") {\n // Prefer OPENAI_API_KEY over embedding.apiKey so Azure (embedding) and OpenAI (chat) can use different keys.\n const fromEnv = readEnvKey(\"OPENAI_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"OPENAI_API_KEY\" };\n // Security: never send gateway/embedding credentials to an arbitrary external endpoint.\n if (!hasCustomExternalBaseURL) {\n if (gatewayToken) return { value: gatewayToken, source: \"gatewayToken\" };\n const fromEmbedding = resolveKey(cfg.embedding?.apiKey);\n if (fromEmbedding) return { value: fromEmbedding, source: \"embedding.apiKey\" };\n }\n return { source: \"none\" };\n }\n\n // Azure Foundry (and Responses) use AZURE_OPENAI_API_KEY so it does not conflict with OPENAI_API_KEY.\n if (prefix === \"azure-foundry\" || prefix === \"azure-foundry-responses\") {\n const fromEnv = readEnvKey(\"AZURE_OPENAI_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"AZURE_OPENAI_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"anthropic\") {\n const fromEnv = readEnvKey(\"ANTHROPIC_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"ANTHROPIC_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"openrouter\") {\n const fromEnv = readEnvKey(\"OPENROUTER_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"OPENROUTER_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"minimax\") {\n const fromEnv = readEnvKey(\"MINIMAX_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"MINIMAX_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"ollama\") {\n // Ollama's OpenAI-compatible endpoint accepts any non-empty string as the API key.\n return { value: \"ollama\", source: \"default\" };\n }\n\n // Generic env fallback: <PREFIX>_API_KEY (covers any provider following this convention).\n // NOTE: the gateway token is intentionally excluded — it is scoped to the local gateway\n // and must never be sent to arbitrary external endpoints.\n const fromGenericEnv = readEnvKey(`${prefix.toUpperCase()}_API_KEY`);\n if (fromGenericEnv) return { value: fromGenericEnv, source: `${prefix.toUpperCase()}_API_KEY` };\n\n return { source: \"none\" };\n}\n\n/**\n * Builds a multi-provider OpenAI-compatible proxy that routes each model to the correct provider API.\n * All existing call sites use `openai.chat.completions.create({ model, ... })` unchanged — this\n * proxy intercepts those calls and selects the right API endpoint + key based on the model prefix.\n *\n * Routing:\n * - `google/*` → Google Gemini OpenAI-compat endpoint (distill.apiKey or llm.providers.google.apiKey)\n * - `openai/*` or bare model (no `/`) → OpenAI (embedding.apiKey or llm.providers.openai.apiKey)\n * - `ollama/*` → local Ollama server (http://127.0.0.1:11434/v1, or llm.providers.ollama.baseURL)\n * - Other `provider/*` with explicit llm.providers config → custom endpoint\n * - Unknown provider, no config → throws UnconfiguredProviderError\n */\nexport function buildMultiProviderOpenAI(\n cfg: HybridMemoryConfig,\n api: ClawdbotPluginApi,\n costTracker: CostTracker | null,\n authBackoffStatePath?: string,\n): OpenAI {\n const clientCache = new Map<string, OpenAI>();\n /** Resolve env:VAR / file:/path / ${VAR} SecretRef strings so all llm.providers keys work with SecretRef format (Issue #344).\n * Delegates to the shared resolveSecretRef helper from config/parsers/core.ts to avoid duplicated logic. */\n const resolveApiKey = (key: string | undefined): string | undefined => {\n // Reject undefined, null, and whitespace-only strings before reaching resolveSecretRef (issues #10, #11).\n if (!key?.trim()) return undefined;\n return resolveSecretRef(key);\n };\n const { gatewayPortRaw, gatewayPort, gatewayAuthResolved, gatewayToken, gatewayBaseUrl } = extractGatewayConfig(cfg);\n // Fail closed: if gateway.auth.token is configured but cannot be resolved, throw rather than\n // silently falling back to OPENCLAW_GATEWAY_TOKEN — a stale env token would mask rollout mistakes.\n if (cfg.gateway?.auth?.token && !gatewayAuthResolved) {\n throw new Error(\n `memory-hybrid: gateway.auth.token is configured (SecretRef \"${cfg.gateway.auth.token}\") but could not be resolved. Ensure the referenced env var or file is accessible, or remove gateway.auth.token from the plugin config. Not falling back to OPENCLAW_GATEWAY_TOKEN to prevent silent auth misconfiguration.`,\n );\n }\n if (gatewayPortRaw && (!gatewayPort || gatewayPort < 1 || gatewayPort > 65535)) {\n api.logger.warn?.(\n `memory-hybrid: OPENCLAW_GATEWAY_PORT must be 1-65535 (got '${gatewayPortRaw}'); falling back to direct OpenAI.`,\n );\n }\n if (gatewayBaseUrl && !gatewayToken) {\n api.logger.warn?.(\n \"memory-hybrid: OPENCLAW_GATEWAY_PORT set but no gateway auth token found; set gateway.auth.token (SecretRef) in plugin config or OPENCLAW_GATEWAY_TOKEN env var. Gateway calls may fail if auth is required.\",\n );\n }\n\n function getOrCreate(key: string, factory: () => OpenAI): OpenAI {\n if (!clientCache.has(key)) clientCache.set(key, factory());\n return clientCache.get(key)!;\n }\n\n function defaultOpenAIClient(): OpenAI {\n if (gatewayBaseUrl) {\n const key = gatewayToken ?? cfg.embedding.apiKey;\n if (!key) throw new UnconfiguredProviderError(\"openai\", \"openai/*\");\n return getOrCreate(\n `openai:gateway:${gatewayBaseUrl}`,\n () =>\n new OpenAI({\n apiKey: key,\n baseURL: gatewayBaseUrl,\n }),\n );\n }\n if (!cfg.embedding.apiKey) throw new UnconfiguredProviderError(\"openai\", \"openai/*\");\n return getOrCreate(\"openai:default\", () => new OpenAI({ apiKey: cfg.embedding.apiKey! }));\n }\n\n /**\n * Normalize bare model names (no \"provider/\" prefix) to \"provider/model\" so the correct API is used.\n * OpenClaw and some configs use bare names (e.g. gemini-3.1-pro-preview); without the prefix we\n * would route to the default OpenAI client and get 404.\n */\n function normalizeModelId(model: string): string {\n const trimmed = model.trim();\n if (trimmed.includes(\"/\")) return trimmed;\n const lower = trimmed.toLowerCase();\n if (lower.startsWith(\"gemini-\")) return `google/${trimmed}`;\n if (lower.startsWith(\"claude-\")) return `anthropic/${trimmed}`;\n if (lower.startsWith(\"gpt-\") || /^o[0-9]+/.test(lower)) return `openai/${trimmed}`;\n if (lower.startsWith(\"minimax-\")) return `minimax/${canonicalizeMiniMaxModelId(trimmed)}`;\n return trimmed;\n }\n\n /**\n * Canonicalize model id for cost logging so pricing table lookup and reports use the correct provider.\n * Gateways may pass e.g. openai/gemini-3.1-pro-preview; we store google/gemini-3.1-pro-preview.\n */\n function canonicalModelIdForCost(providerSlashModel: string): string {\n const trimmed = providerSlashModel.trim();\n const slashIdx = trimmed.indexOf(\"/\");\n const bare = slashIdx >= 0 ? trimmed.slice(slashIdx + 1) : trimmed;\n const lower = bare.toLowerCase();\n if (lower.startsWith(\"gemini-\")) return `google/${bare}`;\n if (lower.startsWith(\"claude-\")) return `anthropic/${bare}`;\n if (lower.startsWith(\"gpt-\") || /^o[0-9]+/.test(lower)) return `openai/${bare}`;\n if (lower.startsWith(\"minimax-\")) return `minimax/${canonicalizeMiniMaxModelId(bare)}`;\n return trimmed.includes(\"/\") ? trimmed : `openai/${trimmed}`;\n }\n\n /** The configured auth.order map from plugin config (issue #311). */\n const authOrder = cfg.auth?.order;\n const preferOAuthWhenBoth = cfg.auth?.preferOAuthWhenBoth !== false;\n const failoverOpts = authBackoffStatePath\n ? {\n statePath: authBackoffStatePath,\n backoffScheduleMinutes: cfg.auth?.backoffScheduleMinutes?.length\n ? cfg.auth.backoffScheduleMinutes\n : DEFAULT_BACKOFF_MINUTES,\n resetBackoffAfterHours: cfg.auth?.resetBackoffAfterHours ?? DEFAULT_RESET_AFTER_HOURS,\n }\n : undefined;\n\n function hasApiKeyForProvider(prefix: string): boolean {\n const providerCfg: LLMProviderConfig | undefined = (\n cfg.llm?.providers as Record<string, LLMProviderConfig | undefined> | undefined\n )?.[prefix];\n const hasCustomExternalBaseURL =\n prefix === \"openai\" && Boolean(providerCfg?.baseURL && providerCfg.baseURL !== gatewayBaseUrl);\n // Exclude gatewayToken from the check for OAuth routing decisions — we only want to detect\n // a real direct API key (llm.providers.X.apiKey, embedding.apiKey, or env var).\n const { value } = resolveProviderApiKey(prefix, providerCfg, cfg, resolveApiKey, {\n gatewayToken: undefined,\n hasCustomExternalBaseURL,\n });\n return Boolean(value && value.length >= 10);\n }\n\n function resolveClient(model: string): {\n client: OpenAI;\n bareModel: string;\n ollamaBaseUrl?: string;\n useFullModel?: boolean;\n authType?: \"oauth\";\n } {\n const normalized = normalizeModelId(model);\n const trimmed = normalized.trim();\n const slashIdx = trimmed.indexOf(\"/\");\n\n if (slashIdx <= 0) {\n return { client: defaultOpenAIClient(), bareModel: trimmed };\n }\n\n const prefix = trimmed.slice(0, slashIdx).toLowerCase();\n const bareModel = trimmed.slice(slashIdx + 1);\n const providerCfg: LLMProviderConfig | undefined = (\n cfg.llm?.providers as Record<string, LLMProviderConfig | undefined> | undefined\n )?.[prefix];\n\n // OAuth + optional failover: when both OAuth and API key exist, prefer OAuth unless in backoff.\n if (hasOAuthProfiles(authOrder?.[prefix], prefix) && gatewayBaseUrl && gatewayToken) {\n const hasApi = hasApiKeyForProvider(prefix);\n const useOAuth = !hasApi || (preferOAuthWhenBoth && (!failoverOpts || !isOAuthInBackoff(prefix, failoverOpts)));\n if (useOAuth) {\n return {\n client: getOrCreate(\n `gateway:oauth:${gatewayBaseUrl}:${prefix}`,\n () => new OpenAI({ apiKey: gatewayToken, baseURL: gatewayBaseUrl }),\n ),\n bareModel,\n useFullModel: true,\n authType: \"oauth\",\n };\n }\n // Fall through to use API client (OAuth in backoff or preferOAuthWhenBoth false).\n }\n\n if (prefix === \"google\") {\n const { value: apiKey } = resolveProviderApiKey(\"google\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"google\", trimmed);\n const baseURL = providerCfg?.baseURL ?? GOOGLE_GEMINI_BASE_URL;\n return {\n client: getOrCreate(`google:${baseURL}`, () => new OpenAI({ apiKey, baseURL })),\n bareModel,\n };\n }\n\n if (prefix === \"openai\") {\n // Only use the gateway token when routing through the local gateway.\n // If a custom external baseURL is configured for the openai provider,\n // do NOT fall back to gatewayToken — that would send the internal gateway\n // token to an arbitrary external endpoint (security issue).\n const hasCustomExternalBaseURL = Boolean(providerCfg?.baseURL && providerCfg.baseURL !== gatewayBaseUrl);\n const { value: apiKey } = resolveProviderApiKey(\"openai\", providerCfg, cfg, resolveApiKey, {\n gatewayToken,\n hasCustomExternalBaseURL,\n });\n if (!apiKey) throw new UnconfiguredProviderError(\"openai\", trimmed);\n const baseURL = providerCfg?.baseURL ?? gatewayBaseUrl;\n const cacheKey = `openai:prefixed:${apiKey.slice(0, 8)}:${baseURL ?? \"default\"}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI({ apiKey, ...(baseURL ? { baseURL } : {}) })),\n bareModel,\n };\n }\n\n if (prefix === \"anthropic\") {\n const { value: apiKey } = resolveProviderApiKey(\"anthropic\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"anthropic\", trimmed);\n let baseURL = providerCfg?.baseURL ?? ANTHROPIC_BASE_URL;\n // Normalize: ensure Anthropic baseURL ends with /v1 for OpenAI-compatible chat endpoint (issue #950)\n baseURL = baseURL.replace(/\\/+$/, \"\");\n if (!baseURL.endsWith(\"/v1\")) {\n baseURL = `${baseURL}/v1`;\n }\n // Anthropic's OpenAI-compatible endpoints require anthropic-version header\n return {\n client: getOrCreate(\n `anthropic:${baseURL}`,\n () =>\n new OpenAI({\n apiKey,\n baseURL,\n defaultHeaders: { \"anthropic-version\": ANTHROPIC_VERSION_HEADER },\n }),\n ),\n bareModel,\n };\n }\n\n if (prefix === \"ollama\") {\n // Ollama exposes an OpenAI-compatible API at /v1. No real API key is required.\n let baseURL = providerCfg?.baseURL ?? `${OLLAMA_DEFAULT_BASE_URL}/v1`;\n // Ensure baseURL ends with /v1 for OpenAI client\n if (!/\\/v1\\/?$/.test(baseURL)) {\n baseURL = `${baseURL.replace(/\\/$/, \"\")}/v1`;\n }\n // Strip /v1 suffix for the health-check base URL\n const ollamaBaseUrl = baseURL.replace(/\\/v1\\/?$/, \"\");\n const { value: apiKey } = resolveProviderApiKey(\"ollama\", providerCfg, cfg, resolveApiKey);\n const cacheKey = `ollama:${baseURL}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI({ apiKey: apiKey ?? \"ollama\", baseURL })),\n bareModel,\n ollamaBaseUrl,\n };\n }\n\n if (prefix === \"openrouter\") {\n // OpenRouter exposes an OpenAI-compatible API at https://openrouter.ai/api/v1.\n // Model names are passed as-is after stripping the \"openrouter/\" prefix\n // (e.g. \"openrouter/anthropic/claude-3.5-sonnet\" → bareModel \"anthropic/claude-3.5-sonnet\").\n const { value: apiKey } = resolveProviderApiKey(\"openrouter\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"openrouter\", trimmed);\n const baseURL = providerCfg?.baseURL ?? OPENROUTER_BASE_URL;\n // Include apiKey prefix in cache key so key rotation takes effect without restart.\n // defaultHeaders follow OpenRouter's recommendations for attribution and rate-limit priority.\n const cacheKey = `openrouter:${baseURL}:${apiKey.slice(0, 8)}`;\n return {\n client: getOrCreate(\n cacheKey,\n () =>\n new OpenAI({\n apiKey,\n baseURL,\n defaultHeaders: {\n \"HTTP-Referer\": \"https://github.com/markus-lassfolk/openclaw-hybrid-memory\",\n \"X-Title\": \"openclaw-hybrid-memory\",\n },\n }),\n ),\n bareModel,\n };\n }\n\n if (prefix === \"minimax\") {\n // Use the built-in MiniMax API endpoint as default so callers never accidentally\n // fall through to the default OpenAI client (which returns 404 for MiniMax models).\n const { value: apiKey } = resolveProviderApiKey(\"minimax\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"minimax\", trimmed);\n const baseURL = providerCfg?.baseURL ?? MINIMAX_BASE_URL;\n // Canonicalize the bare model name: strip Ollama-style \":tag\" suffixes and fix casing\n // so that e.g. \"minimax-m2.5:cloud\" → \"MiniMax-M2.5\" (issue #400).\n const canonicalBareModel = canonicalizeMiniMaxModelId(bareModel);\n return {\n client: getOrCreate(`minimax:${baseURL}`, () => new OpenAI({ apiKey, baseURL })),\n bareModel: canonicalBareModel,\n };\n }\n\n // For all remaining providers (custom configs and unknown providers), use the centralised\n // resolver which covers llm.providers[prefix].apiKey and the <PREFIX>_API_KEY env convention.\n // The gateway token is intentionally excluded — it is scoped to the local gateway and must\n // never be sent to arbitrary external endpoints.\n const { value: resolvedApiKey } = resolveProviderApiKey(prefix, providerCfg, cfg, resolveApiKey);\n if (readProviderBaseUrl(providerCfg) || resolvedApiKey) {\n // apiKey may be absent when the provider only needs a custom baseURL (some self-hosted servers)\n const apiKey = resolvedApiKey ?? \"no-key\";\n const baseURL = readProviderBaseUrl(providerCfg);\n // Azure OpenAI / Foundry resource hosts: api-key header (SDK still adds Bearer; many endpoints accept both).\n const isAzureResource = typeof baseURL === \"string\" && isAzureOpenAiResourceEndpoint(baseURL);\n // Azure API Management (*.azure-api.net): must strip Bearer — use same fetch as embeddings factory.\n const isApim = typeof baseURL === \"string\" && isAzureApiManagementGatewayUrl(baseURL);\n const clientOpts: {\n apiKey: string;\n baseURL?: string;\n defaultHeaders?: Record<string, string>;\n fetch?: typeof globalThis.fetch;\n } = {\n apiKey,\n ...(baseURL ? { baseURL } : {}),\n };\n if (apiKey !== \"no-key\") {\n if (isAzureResource) clientOpts.defaultHeaders = { \"api-key\": apiKey };\n if (isApim) {\n clientOpts.defaultHeaders = { ...(clientOpts.defaultHeaders ?? {}), \"api-key\": apiKey };\n clientOpts.fetch = createApimGatewayFetch(apiKey);\n }\n }\n const cacheKey = `custom:${prefix}:${apiKey.slice(0, 8)}:${baseURL ?? \"default\"}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI(clientOpts)),\n bareModel,\n };\n }\n\n // Unknown provider with no config — throw so callers can skip to the next model cleanly\n throw new UnconfiguredProviderError(prefix, trimmed);\n }\n\n /**\n * Newer OpenAI models (o-series, gpt-5+, gpt-4.1*) use `max_completion_tokens` instead of `max_tokens`.\n * Reasoning models (o1, o3, o4-*) and GPT-5 chat deployments (Azure) reject custom temperature/top_p — strip those params.\n * Applied for every routed provider (Azure Foundry, etc.), not only `openai/` — see model-capabilities.\n */\n function remapMaxTokensForOpenAI(body: Record<string, unknown>): Record<string, unknown> {\n let result = body;\n const modelId = String(result.model ?? \"\");\n if (requiresMaxCompletionTokens(modelId) && \"max_tokens\" in result && !(\"max_completion_tokens\" in result)) {\n const { max_tokens, ...rest } = result;\n result = { ...rest, max_completion_tokens: max_tokens };\n }\n if (shouldOmitSamplingParams(modelId)) {\n const { temperature, top_p, ...rest } = result as Record<string, unknown> & {\n temperature?: unknown;\n top_p?: unknown;\n };\n if (temperature !== undefined || top_p !== undefined) {\n api.logger.debug?.(`memory-hybrid: stripped temperature/top_p for model ${modelId}`);\n }\n result = rest;\n }\n return result;\n }\n\n /**\n * Shared cost-tracking wrapper for both chat and responses calls.\n * Fire-and-forget — never blocks or modifies the returned promise.\n */\n function trackCost(promise: Promise<unknown>, body: Record<string, unknown>, model: string, start: number): void {\n if (!costTracker) return;\n const feature = inferFeatureLabel(body, model);\n const normalizedModel = canonicalModelIdForCost(model.includes(\"/\") ? model : `openai/${model.trim()}`);\n void Promise.resolve(promise).then(\n (resp: unknown) => {\n try {\n const durationMs = Date.now() - start;\n const r = resp as {\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n input_tokens?: number;\n output_tokens?: number;\n };\n } | null;\n costTracker.record({\n feature,\n model: normalizedModel,\n inputTokens: r?.usage?.prompt_tokens ?? r?.usage?.input_tokens ?? 0,\n outputTokens: r?.usage?.completion_tokens ?? r?.usage?.output_tokens ?? 0,\n durationMs,\n success: true,\n });\n } catch {\n /* never let tracking break LLM calls */\n }\n },\n () => {\n try {\n const durationMs = Date.now() - start;\n const reqMessages = Array.isArray(body.messages) ? (body.messages as unknown[]) : [];\n const reqInput = Array.isArray(body.input) ? (body.input as unknown[]) : [];\n const content = reqMessages.length > 0 ? reqMessages : reqInput;\n const estimatedInputTokens = Math.ceil(JSON.stringify(content).length / 4);\n costTracker.record({\n feature,\n model: normalizedModel,\n inputTokens: estimatedInputTokens,\n outputTokens: 0,\n durationMs,\n success: false,\n });\n } catch {\n /* never let tracking break LLM calls */\n }\n },\n );\n }\n\n // Proxy that intercepts chat.completions.create and responses.create, routing to the right provider client.\n // All other OpenAI methods (embeddings, etc.) are NOT proxied — embeddings use a separate client.\n // The proxy base is only accessed for non-chat methods (not used by this plugin directly).\n // Only create it with a real key when one is available; otherwise omit to avoid \"unused\" placeholder.\n const proxyBaseKey = cfg.embedding.apiKey ?? gatewayToken ?? \"\";\n const proxyBase: OpenAI = proxyBaseKey ? new OpenAI({ apiKey: proxyBaseKey }) : ({} as OpenAI);\n return new Proxy(proxyBase, {\n get(target, prop, receiver) {\n if (prop === \"chat\") {\n return {\n completions: {\n create(\n body: Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0],\n opts?: Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[1],\n ) {\n const rawModel: string = (body as { model?: string }).model ?? \"\";\n const model = normalizeModelId(rawModel);\n const { client, bareModel, ollamaBaseUrl, useFullModel, authType } = resolveClient(model);\n const prefix = model.trim().split(\"/\")[0]?.toLowerCase();\n // When gateway-routed for non-OpenAI providers (auth.order OAuth), send the full \"provider/model\"\n // name so the gateway can route to the correct provider using the configured auth profile.\n const modelForRequest = useFullModel ? model.trim() : bareModel;\n const merged = { ...(body as object), model: modelForRequest } as Record<string, unknown>;\n const adjustedBody = remapMaxTokensForOpenAI(merged);\n const start = Date.now();\n\n // Responses-only models: route chat.completions.create → responses.create so direct SDK\n // call sites (classification, auto-classifier, etc.) work with azure-foundry-responses/* (#1043, Codex P1).\n if (resolveWireApi(model) === \"responses\") {\n if ((adjustedBody as { stream?: boolean }).stream) {\n return Promise.reject(\n new Error(\n \"memory-hybrid: stream=true is not supported for Responses API models (e.g. azure-foundry-responses/*); set stream: false.\",\n ),\n );\n }\n const responsesBody = buildResponsesRequestFromChatBody(adjustedBody);\n const input = responsesBody.input;\n if (!Array.isArray(input) || input.length === 0) {\n return Promise.reject(new Error(\"memory-hybrid: Responses API request requires non-empty messages\"));\n }\n const responsesNs = (\n client as unknown as { responses?: { create: (b: unknown, o?: unknown) => Promise<unknown> } }\n ).responses;\n if (!responsesNs?.create) {\n return Promise.reject(\n new Error(\n `Provider \"${prefix}\" does not expose responses.create(). Ensure the endpoint supports the OpenAI Responses API and the openai SDK is >=6.16.0.`,\n ),\n );\n }\n const modelLabel = String(adjustedBody.model ?? modelForRequest);\n let promise: Promise<unknown> = responsesNs.create(responsesBody, opts ?? {});\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n });\n }\n promise = promise.then((raw) => responsesRawToChatCompletion(raw as ResponsesApiResponse, modelLabel));\n trackCost(promise, body as unknown as Record<string, unknown>, model, start);\n return promise as ReturnType<OpenAI[\"chat\"][\"completions\"][\"create\"]>;\n }\n\n // For Ollama models, probe the local server before attempting the call so we fall\n // through to the next tier model quickly instead of waiting for a TCP timeout.\n const makeCall = () =>\n client.chat.completions.create(\n adjustedBody as unknown as Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0],\n opts,\n );\n let promise: ReturnType<typeof makeCall> = ollamaBaseUrl\n ? ((async () => {\n const available = await probeOllamaEndpoint(ollamaBaseUrl);\n if (!available) {\n const err = Object.assign(\n new Error(`Ollama not available at ${ollamaBaseUrl} (ECONNREFUSED) — try next model`),\n { code: \"ECONNREFUSED\" },\n );\n throw err;\n }\n return makeCall();\n })() as ReturnType<typeof makeCall>)\n : makeCall();\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n }) as ReturnType<typeof makeCall>;\n }\n trackCost(promise as Promise<unknown>, body as unknown as Record<string, unknown>, model, start);\n return promise;\n },\n },\n };\n }\n\n if (prop === \"responses\") {\n return {\n create(body: Record<string, unknown>, opts?: { signal?: AbortSignal }) {\n const rawModel: string = String(body.model ?? \"\");\n const model = normalizeModelId(rawModel);\n const { client, bareModel, useFullModel, authType } = resolveClient(model);\n const prefix = model.trim().split(\"/\")[0]?.toLowerCase();\n const modelForRequest = useFullModel ? model.trim() : bareModel;\n const merged = { ...body, model: modelForRequest };\n const adjustedBody = remapMaxTokensForOpenAI(merged);\n const start = Date.now();\n\n const responsesNs = (\n client as unknown as { responses?: { create: (b: unknown, o?: unknown) => Promise<unknown> } }\n ).responses;\n if (!responsesNs?.create) {\n return Promise.reject(\n new Error(\n `Provider \"${prefix}\" does not expose responses.create(). Ensure the endpoint supports the OpenAI Responses API and the openai SDK is >=6.16.0.`,\n ),\n );\n }\n\n let promise = responsesNs.create(adjustedBody, opts ?? {});\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n });\n }\n trackCost(promise, body, model, start);\n return promise;\n },\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n }) as OpenAI;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"provider-router.js","names":[],"sources":["../../setup/provider-router.ts"],"sourcesContent":["/** @module provider-router — Multi-provider LLM routing (OpenAI-compatible) and API key resolution. */\nimport OpenAI from \"openai\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { CostTracker } from \"../backends/cost-tracker.js\";\nimport type { HybridMemoryConfig, LLMProviderConfig, ResolvedGatewayAuthConfig } from \"../config.js\";\nimport {\n EMBEDDING_DIMENSIONS,\n OPENAI_MODELS,\n normalizeResolvedSecretValue,\n resolveSecretRef,\n} from \"../config/parsers/core.js\";\nimport { UnconfiguredProviderError } from \"../services/chat.js\";\nimport { isAzureOpenAiResourceEndpoint } from \"../services/embeddings/shared.js\";\nimport {\n requiresMaxCompletionTokens,\n resolveWireApi,\n shouldOmitSamplingParams,\n} from \"../services/model-capabilities.js\";\nimport {\n type ResponsesApiResponse,\n buildResponsesRequestFromChatBody,\n responsesRawToChatCompletion,\n} from \"../services/responses-adapter.js\";\nimport { createApimGatewayFetch, isAzureApiManagementGatewayUrl } from \"../utils/apim-gateway-fetch.js\";\nimport {\n DEFAULT_BACKOFF_MINUTES,\n DEFAULT_RESET_AFTER_HOURS,\n isOAuthInBackoff,\n recordOAuthFailure,\n} from \"../utils/auth-failover.js\";\nimport { hasOAuthProfiles } from \"../utils/auth.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { inferFeatureLabel } from \"./cost-instrumentation.js\";\n\n/** Minimal logger shape accepted by the log-once helpers. */\ninterface InfoLogger {\n logger?: { info?: (msg: string) => void };\n}\n\n/**\n * Process-lifetime set of log keys that have already been emitted.\n * Prevents the same gateway-provider info message from flooding logs when the plugin\n * initialises multiple times in the same process (e.g. once per CLI invocation in a step).\n * Reset via resetGatewayLogOnceForTesting() in unit tests for isolation.\n */\nconst _loggedOnceKeys = new Set<string>();\n\n/**\n * Emit `msg` via `api.logger.info` at most once per process for the given `key`.\n * Subsequent calls with the same key are silently dropped.\n */\nfunction logInfoOnce(key: string, msg: string, api: InfoLogger): void {\n if (_loggedOnceKeys.has(key)) return;\n _loggedOnceKeys.add(key);\n api.logger?.info?.(msg);\n}\n\n/**\n * Reset the log-once guard. Call this in tests to ensure each test starts clean.\n */\nexport function resetGatewayLogOnceForTesting(): void {\n _loggedOnceKeys.clear();\n}\n\n/**\n * Public wrapper around logInfoOnce for use outside this module (e.g. bootstrap-databases).\n * Emits `msg` via `api.logger.info` at most once per process for the given `key`.\n */\nexport function gatewayLogInfoOnce(key: string, msg: string, api: InfoLogger): void {\n logInfoOnce(key, msg, api);\n}\n\n/**\n * Normalize baseURL vs baseUrl (OpenClaw config uses camelCase `baseUrl`; SDK uses `baseURL`).\n * Intentionally duplicated from config/parsers/index.ts to avoid a circular module dependency —\n * init-databases bootstraps before the full config parser is available.\n */\nexport function readProviderBaseUrl(p: { baseURL?: string; baseUrl?: string } | undefined): string | undefined {\n if (!p) return undefined;\n const u = typeof p.baseURL === \"string\" ? p.baseURL : typeof p.baseUrl === \"string\" ? p.baseUrl : undefined;\n const t = u?.trim();\n return t && t.length > 0 ? t : undefined;\n}\n\n/**\n * Embeddings are created before `models.providers` is merged into `cfg.llm`. If `embedding.endpoint`\n * was stripped by the host validator or omitted, inherit the APIM / Foundry base from the global\n * `models.providers[\"azure-foundry\"]` entry so requests do not fall through to api.openai.com with\n * an Azure or subscription key (401 \"Incorrect API key\" from platform.openai.com).\n */\n/** OpenClaw gateway `models.providers` (or legacy `llm.providers` / top-level `providers`). */\nexport function getGatewayModelsProviders(\n gwConfig: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!gwConfig) return undefined;\n const p =\n (gwConfig.models as Record<string, unknown> | undefined)?.providers ??\n (gwConfig.llm as Record<string, unknown> | undefined)?.providers ??\n gwConfig.providers;\n if (!p || typeof p !== \"object\" || Array.isArray(p)) return undefined;\n return p as Record<string, unknown>;\n}\n\nexport function patchEmbeddingEndpointFromGatewayProviders(cfg: HybridMemoryConfig, api: ClawdbotPluginApi): void {\n const ep = cfg.embedding?.endpoint;\n if (typeof ep === \"string\" && ep.trim().length > 0) return;\n // Only inherit Azure Foundry endpoint for OpenAI provider\n if (cfg.embedding?.provider !== \"openai\") return;\n const gwConfig = api.config as Record<string, unknown> | undefined;\n const gwProviders = getGatewayModelsProviders(gwConfig);\n const af = gwProviders?.[\"azure-foundry\"] as { baseURL?: string; baseUrl?: string } | undefined;\n const base = readProviderBaseUrl(af);\n if (!base) return;\n (cfg.embedding as Record<string, unknown>).endpoint = base;\n api.logger?.info?.(\n `memory-hybrid: embedding.endpoint was empty — using models.providers[\"azure-foundry\"] base URL (${base})`,\n );\n}\n\n/** Existing `llm.providers` key whose name matches `normalizedName` case-insensitively (issue #1002 / PR #1003). */\nfunction findLlmProviderSlotKey(\n prov: Record<string, Record<string, unknown>>,\n normalizedName: string,\n): string | undefined {\n for (const k of Object.keys(prov)) {\n if (k.toLowerCase() === normalizedName) return k;\n }\n return undefined;\n}\n\nfunction llmProviderEntryAsPlainObject(raw: unknown): Record<string, unknown> {\n if (raw && typeof raw === \"object\" && !Array.isArray(raw)) return { ...(raw as Record<string, unknown>) };\n return {};\n}\n\n/**\n * Merge gateway `models.providers` apiKey/baseURL into plugin `llm.providers` (issues #487, #386).\n * Optionally records merged provider names for bootstrap tier-list augmentation.\n * Resolves mixed-case plugin keys (e.g. `OpenAI`) so gateway merge does not add a duplicate lowercase entry.\n */\nexport function mergeGatewayProviderCredentialsIntoLlmProvidersMap(\n prov: Record<string, Record<string, unknown>>,\n gwProviders: Record<string, unknown> | undefined,\n api: Pick<ClawdbotPluginApi, \"logger\">,\n mergedNames?: string[],\n mergedOriginals?: Map<string, string>,\n): number {\n let newApiKeySlots = 0;\n if (!gwProviders || typeof gwProviders !== \"object\" || Array.isArray(gwProviders)) return 0;\n for (const [name, gw] of Object.entries(gwProviders)) {\n if (!name || !gw || typeof gw !== \"object\") continue;\n const rawKey = (gw as Record<string, unknown>).apiKey ?? (gw as Record<string, unknown>).api_key;\n if (typeof rawKey !== \"string\" || !rawKey.trim()) continue;\n const normalizedName = name.toLowerCase();\n const slotKey = findLlmProviderSlotKey(prov, normalizedName);\n const targetKey = slotKey ?? normalizedName;\n const cur = llmProviderEntryAsPlainObject(prov[targetKey]);\n const pluginHasKey = typeof cur.apiKey === \"string\" && (cur.apiKey as string).trim().length > 0;\n if (!pluginHasKey) {\n newApiKeySlots++;\n prov[targetKey] = {\n ...cur,\n apiKey: rawKey.trim(),\n baseURL:\n (typeof cur.baseURL === \"string\" && cur.baseURL.trim() ? cur.baseURL : undefined) ??\n (gw as Record<string, unknown>).baseURL ??\n (gw as Record<string, unknown>).base_url ??\n (gw as Record<string, unknown>).baseUrl,\n };\n mergedNames?.push(normalizedName);\n mergedOriginals?.set(normalizedName, name);\n logInfoOnce(\n `gateway-provider:${normalizedName}`,\n `memory-hybrid: using gateway provider \"${name}\" for llm.providers (add ${normalizedName}/<model> to llm.default or llm.heavy to use)`,\n api,\n );\n } else {\n const gwBase =\n (gw as Record<string, unknown>).baseURL ??\n (gw as Record<string, unknown>).base_url ??\n (gw as Record<string, unknown>).baseUrl;\n const existingBase = typeof cur.baseURL === \"string\" && cur.baseURL.trim() ? cur.baseURL : undefined;\n if (typeof gwBase === \"string\" && gwBase.trim() && !existingBase) {\n prov[targetKey] = { ...cur, baseURL: gwBase.trim() };\n }\n mergedNames?.push(normalizedName);\n mergedOriginals?.set(normalizedName, name);\n }\n }\n return newApiKeySlots;\n}\n\nfunction stripEmbeddingModelPrefix(model: string): string {\n const t = model.trim();\n const slash = t.indexOf(\"/\");\n if (slash > 0 && slash < t.length - 1) return t.slice(slash + 1).trim();\n return t;\n}\n\nfunction mapMemorySearchProviderToEmbeddingProvider(providerRaw: string): \"openai\" | \"google\" | \"ollama\" | null {\n const x = providerRaw.trim().toLowerCase().replace(/_/g, \"-\");\n if (x === \"openai\" || x === \"azure-foundry\" || x === \"azure\" || x === \"azureopenai\" || x === \"azure-openai\")\n return \"openai\";\n if (x === \"google\" || x === \"gemini\" || x === \"vertex\") return \"google\";\n if (x === \"ollama\") return \"ollama\";\n return null;\n}\n\nfunction inferEmbeddingProviderFromBareModel(modelBare: string): \"openai\" | \"google\" | \"ollama\" | null {\n if (OPENAI_MODELS.has(modelBare)) return \"openai\";\n const m = modelBare.toLowerCase();\n if (m.includes(\"gemini\") && m.includes(\"embed\")) return \"google\";\n if (\n m.includes(\"nomic-embed\") ||\n m.includes(\"mxbai-embed\") ||\n m === \"all-minilm\" ||\n m.includes(\"snowflake-arctic-embed\")\n )\n return \"ollama\";\n if (m.startsWith(\"text-embedding\") || m.startsWith(\"embedding-\")) return \"openai\";\n return null;\n}\n\nfunction findGatewayProviderEntryLoose(\n gwProviders: Record<string, unknown>,\n providerHint: string,\n): Record<string, unknown> | undefined {\n const hint = providerHint.trim().toLowerCase().replace(/_/g, \"-\");\n for (const [k, v] of Object.entries(gwProviders)) {\n if (!v || typeof v !== \"object\" || Array.isArray(v)) continue;\n if (k.toLowerCase().replace(/_/g, \"-\") === hint) return v as Record<string, unknown>;\n }\n return undefined;\n}\n\n/**\n * Shallow-clone plugin config branches that global inheritance mutates (issue #1002).\n */\nexport function shallowClonePluginConfigForGatewayMerge(raw: Record<string, unknown>): Record<string, unknown> {\n const out = { ...raw };\n if (out.embedding && typeof out.embedding === \"object\" && !Array.isArray(out.embedding)) {\n out.embedding = { ...(out.embedding as Record<string, unknown>) };\n }\n if (out.llm && typeof out.llm === \"object\" && !Array.isArray(out.llm)) {\n const llm = { ...(out.llm as Record<string, unknown>) };\n if (llm.providers && typeof llm.providers === \"object\" && !Array.isArray(llm.providers)) {\n const p = { ...(llm.providers as Record<string, unknown>) };\n for (const key of Object.keys(p)) {\n const v = p[key];\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n p[key] = { ...(v as Record<string, unknown>) };\n }\n }\n llm.providers = p;\n }\n out.llm = llm;\n }\n return out;\n}\n\n/**\n * Before `hybridConfigSchema.parse`: merge gateway credentials into raw `llm.providers`, then\n * overlay `agents.defaults.memorySearch` onto `embedding` for omitted fields (issue #1002).\n * Plugin `embedding` / `llm.providers` entries always win when already set.\n */\nexport function applyGatewayEmbeddingInheritanceBeforeParse(\n raw: Record<string, unknown>,\n api: ClawdbotPluginApi,\n): void {\n const gw = api.config as Record<string, unknown> | undefined;\n const gwProviders = getGatewayModelsProviders(gw);\n if (gwProviders) {\n if (!raw.llm || typeof raw.llm !== \"object\" || Array.isArray(raw.llm)) {\n raw.llm = { providers: {} };\n } else {\n const plm0 = raw.llm as Record<string, unknown>;\n if (!plm0.providers || typeof plm0.providers !== \"object\" || Array.isArray(plm0.providers)) {\n plm0.providers = {};\n }\n }\n const plm = raw.llm as Record<string, unknown>;\n const prov = plm.providers as Record<string, Record<string, unknown>>;\n const n = mergeGatewayProviderCredentialsIntoLlmProvidersMap(prov, gwProviders, api);\n if (n > 0) {\n logInfoOnce(\n \"merged-gateway-providers\",\n `memory-hybrid: merged ${n} gateway provider credential(s) into plugin llm.providers before config parse (issue #1002)`,\n api,\n );\n }\n }\n\n const agents = gw?.agents as Record<string, unknown> | undefined;\n const defaults = agents?.defaults as Record<string, unknown> | undefined;\n const ms = defaults?.memorySearch as Record<string, unknown> | undefined;\n if (!ms || ms.enabled === false) return;\n\n const msProvider = typeof ms.provider === \"string\" ? ms.provider.trim() : \"\";\n const msModel = typeof ms.model === \"string\" ? ms.model.trim() : \"\";\n if (!msProvider && !msModel) return;\n\n let emb: Record<string, unknown>;\n if (!raw.embedding || typeof raw.embedding !== \"object\" || Array.isArray(raw.embedding)) {\n emb = {};\n raw.embedding = emb;\n } else {\n emb = { ...(raw.embedding as Record<string, unknown>) };\n raw.embedding = emb;\n }\n\n const modelBare = msModel ? stripEmbeddingModelPrefix(msModel) : \"\";\n let touched = false;\n\n if (msModel && emb.model === undefined) {\n emb.model = modelBare;\n touched = true;\n }\n\n let mapped = msProvider ? mapMemorySearchProviderToEmbeddingProvider(msProvider) : null;\n if (!mapped && modelBare) mapped = inferEmbeddingProviderFromBareModel(modelBare);\n if (mapped && emb.provider === undefined) {\n emb.provider = mapped;\n touched = true;\n }\n\n if (modelBare && emb.dimensions === undefined) {\n const d = EMBEDDING_DIMENSIONS[modelBare];\n if (typeof d === \"number\") {\n emb.dimensions = d;\n touched = true;\n }\n }\n\n if (gwProviders && msProvider && emb.deployment === undefined) {\n const gwp = findGatewayProviderEntryLoose(gwProviders, msProvider);\n if (gwp) {\n const dep =\n (typeof gwp.deployment === \"string\" && gwp.deployment.trim()) ||\n (typeof gwp.deploymentName === \"string\" && gwp.deploymentName.trim()) ||\n (typeof (gwp as { deploymentId?: string }).deploymentId === \"string\" &&\n (gwp as { deploymentId: string }).deploymentId.trim());\n if (dep) {\n emb.deployment = dep;\n touched = true;\n }\n }\n }\n\n const inheritedProvId = typeof emb.provider === \"string\" ? emb.provider.trim() : \"\";\n if (inheritedProvId && emb.apiKey === undefined) {\n const plmMerged = raw.llm && typeof raw.llm === \"object\" && !Array.isArray(raw.llm) ? raw.llm : null;\n const provMerged =\n plmMerged &&\n typeof (plmMerged as Record<string, unknown>).providers === \"object\" &&\n !Array.isArray((plmMerged as Record<string, unknown>).providers)\n ? ((plmMerged as Record<string, unknown>).providers as Record<string, unknown>)\n : {};\n const slot = findGatewayProviderEntryLoose(provMerged, inheritedProvId);\n const ak = slot && typeof slot.apiKey === \"string\" ? slot.apiKey.trim() : \"\";\n if (ak) {\n emb.apiKey = ak;\n touched = true;\n }\n }\n\n if (touched) {\n api.logger?.info?.(\n \"memory-hybrid: inherited embedding fields from agents.defaults.memorySearch (issue #1002); plugin embedding.* still overrides when set\",\n );\n }\n}\n\n/**\n * Provider prefixes that resolveClient() handles natively without explicit llm.providers config.\n * Keep in sync with the built-in provider cases in resolveClient() in this file.\n * If resolveClient() adds a new built-in provider, add it here too.\n */\nexport const ROUTABLE_BUILTIN_PROVIDERS = new Set([\"google\", \"openai\", \"anthropic\", \"ollama\", \"openrouter\", \"minimax\"]);\n\n/**\n * Extract gateway configuration from environment and plugin config.\n * Centralized to avoid duplicating this logic across buildMultiProviderOpenAI and initializeDatabases.\n */\nexport function extractGatewayConfig(cfg: HybridMemoryConfig): {\n gatewayPortRaw: string | undefined;\n gatewayPort: number | undefined;\n gatewayAuthResolved: string | undefined;\n gatewayToken: string | undefined;\n gatewayBaseUrl: string | undefined;\n} {\n const gatewayPortRaw = normalizeResolvedSecretValue(getEnv(\"OPENCLAW_GATEWAY_PORT\"));\n const gatewayPort = gatewayPortRaw ? Number.parseInt(gatewayPortRaw, 10) : undefined;\n const gatewayAuthResolved = (cfg.gateway?.auth as ResolvedGatewayAuthConfig | undefined)?._resolvedToken;\n const gatewayToken = gatewayAuthResolved ?? normalizeResolvedSecretValue(getEnv(\"OPENCLAW_GATEWAY_TOKEN\"));\n const gatewayBaseUrl =\n gatewayPort && gatewayPort >= 1 && gatewayPort <= 65535 ? `http://127.0.0.1:${gatewayPort}/v1` : undefined;\n return {\n gatewayPortRaw,\n gatewayPort,\n gatewayAuthResolved,\n gatewayToken,\n gatewayBaseUrl,\n };\n}\n\n/** Known provider OpenAI-compatible base URLs. */\nconst GOOGLE_GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\";\n/** Default Ollama server base URL (without /v1 path). */\nexport const OLLAMA_DEFAULT_BASE_URL = \"http://127.0.0.1:11434\";\n/** How long to cache an Ollama health-check result (positive or negative). */\nconst OLLAMA_HEALTH_CACHE_TTL_MS = 30_000;\n/** Timeout for a single Ollama /api/tags health ping. */\nexport const OLLAMA_HEALTH_TIMEOUT_MS = 2_000;\n\n/**\n * Module-level health cache so repeated calls within the TTL window skip the network round-trip.\n * Shared across plugin reloads in the same process (intentional).\n */\nconst _ollamaHealthCache = new Map<string, { ok: boolean; ts: number }>();\n\n/**\n * Probe an Ollama server via GET /api/tags (the Ollama health endpoint).\n * Returns true when Ollama is reachable and responsive, false otherwise.\n * Results are cached for OLLAMA_HEALTH_CACHE_TTL_MS to avoid hammering the endpoint.\n */\nexport async function probeOllamaEndpoint(baseUrl: string): Promise<boolean> {\n const now = Date.now();\n const cached = _ollamaHealthCache.get(baseUrl);\n if (cached && now - cached.ts < OLLAMA_HEALTH_CACHE_TTL_MS) return cached.ok;\n try {\n const resp = await fetch(`${baseUrl}/api/tags`, {\n signal: AbortSignal.timeout(OLLAMA_HEALTH_TIMEOUT_MS),\n });\n const ok = resp.ok;\n _ollamaHealthCache.set(baseUrl, { ok, ts: now });\n return ok;\n } catch {\n _ollamaHealthCache.set(baseUrl, { ok: false, ts: now });\n return false;\n }\n}\n\n/** Invalidate cached Ollama health result (e.g. after auto-start). */\nexport function clearOllamaHealthCacheEntry(baseUrl: string): void {\n _ollamaHealthCache.delete(baseUrl);\n}\n\nconst ANTHROPIC_BASE_URL = \"https://api.anthropic.com/v1\";\nconst ANTHROPIC_VERSION_HEADER = \"2023-06-01\";\n\n/** Built-in OpenAI-compatible base URL for MiniMax API (global endpoint). */\nexport const MINIMAX_BASE_URL = \"https://api.minimax.io/v1\";\n\n/**\n * Canonical MiniMax model name mapping (lowercase key → proper-case value).\n * Covers Ollama-style aliases (e.g. \"minimax-m2.5:cloud\") that users may configure\n * and that would otherwise produce a 404 from the MiniMax API (issue #400).\n */\nconst MINIMAX_MODEL_ALIASES: Record<string, string> = {\n \"minimax-m2.5\": \"MiniMax-M2.5\",\n \"minimax-text-01\": \"MiniMax-Text-01\",\n};\n\n/**\n * Canonicalize a bare MiniMax model name.\n * - Strips Ollama-style `:tag` suffixes (e.g. `:cloud`, `:latest`) which are invalid on the MiniMax API.\n * - Looks up the result in MINIMAX_MODEL_ALIASES to restore correct casing (e.g. \"minimax-m2.5\" → \"MiniMax-M2.5\").\n * - Falls back to the original bare name (without tag) if no alias matches.\n */\nfunction canonicalizeMiniMaxModelId(bare: string): string {\n // Strip Ollama-style \":tag\" suffix (e.g. \"minimax-m2.5:cloud\" → \"minimax-m2.5\")\n const withoutTag = bare.includes(\":\") ? bare.slice(0, bare.indexOf(\":\")) : bare;\n const canonical = MINIMAX_MODEL_ALIASES[withoutTag.toLowerCase()];\n return canonical ?? withoutTag;\n}\n\n/** OpenRouter OpenAI-compatible base URL. */\nexport const OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\n\n/** Resolved API key with metadata about which configuration source provided it. */\ntype ResolvedApiKey = { value?: string; source: string };\n\n/**\n * Centralised API-key resolver for all built-in and custom providers.\n *\n * Resolves the API key for a named provider using a well-defined precedence chain.\n * Provider-specific exceptions are explicit and documented here, rather than scattered\n * across individual provider branches in `resolveClient`.\n *\n * Precedence table (highest → lowest):\n *\n * | Source | google | openai | anthropic | openrouter | minimax | ollama | custom |\n * |-----------------------------|:------:|:------:|:---------:|:----------:|:-------:|:------:|:------:|\n * | llm.providers.X.apiKey | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n * | distill.apiKey (legacy) | ✓ | | | | | | |\n * | gatewayToken | | ✓† | | | | | |\n * | embedding.apiKey | | ✓† | | | | | |\n * | GOOGLE_API_KEY env | ✓ | | | | | | |\n * | OPENAI_API_KEY env | | ✓* | | | | | |\n * | AZURE_OPENAI_API_KEY env | | | | | | | ✓‡ |\n * | ANTHROPIC_API_KEY env | | | ✓ | | | | |\n * | OPENROUTER_API_KEY env | | | | ✓ | | | |\n * | MINIMAX_API_KEY env | | | | | ✓ | | |\n * | <PREFIX>_API_KEY env | | | | | | | ✓ |\n * | \"ollama\" (no-op default) | | | | | | ✓ | |\n *\n * * openai: OPENAI_API_KEY is preferred over embedding.apiKey so Azure and OpenAI keys do not conflict.\n * † openai: `gatewayToken` and `embedding.apiKey` are skipped when `hasCustomExternalBaseURL` is true\n * (security: never send internal gateway credentials to external endpoints).\n * ‡ azure-foundry / azure-foundry-responses: AZURE_OPENAI_API_KEY env when llm.providers.*.apiKey not set.\n *\n * @param prefix Lowercase provider prefix, e.g. \"google\", \"openai\".\n * @param providerCfg The llm.providers[prefix] config object, if present.\n * @param cfg Full plugin config.\n * @param resolveKey SecretRef resolver (env:VAR / file:// / ${VAR}).\n * @param opts.gatewayToken Resolved gateway auth token (openai only).\n * @param opts.hasCustomExternalBaseURL True when openai uses a non-gateway baseURL.\n * @param opts.env Process environment (injectable for tests; defaults to process.env).\n */\nexport function resolveProviderApiKey(\n prefix: string,\n providerCfg: LLMProviderConfig | undefined,\n cfg: HybridMemoryConfig,\n resolveKey: (key: string | undefined) => string | undefined,\n opts: {\n gatewayToken?: string;\n hasCustomExternalBaseURL?: boolean;\n env?: NodeJS.ProcessEnv;\n } = {},\n): ResolvedApiKey {\n const { gatewayToken, hasCustomExternalBaseURL = false, env = process.env } = opts;\n const readEnvKey = (name: string): string | undefined => normalizeResolvedSecretValue(env[name]);\n\n // Highest priority: explicit per-provider key in llm.providers config (all providers).\n const fromProviderCfg = resolveKey(providerCfg?.apiKey);\n if (fromProviderCfg) return { value: fromProviderCfg, source: `llm.providers.${prefix}.apiKey` };\n\n if (prefix === \"google\") {\n // Legacy fallback: distill.apiKey doubles as the Google API key for distillation.\n const fromDistill = resolveKey(cfg.distill?.apiKey);\n if (fromDistill) return { value: fromDistill, source: \"distill.apiKey\" };\n const fromEnv = readEnvKey(\"GOOGLE_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"GOOGLE_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"openai\") {\n // Prefer OPENAI_API_KEY over embedding.apiKey so Azure (embedding) and OpenAI (chat) can use different keys.\n const fromEnv = readEnvKey(\"OPENAI_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"OPENAI_API_KEY\" };\n // Security: never send gateway/embedding credentials to an arbitrary external endpoint.\n if (!hasCustomExternalBaseURL) {\n if (gatewayToken) return { value: gatewayToken, source: \"gatewayToken\" };\n const fromEmbedding = resolveKey(cfg.embedding?.apiKey);\n if (fromEmbedding) return { value: fromEmbedding, source: \"embedding.apiKey\" };\n }\n return { source: \"none\" };\n }\n\n // Azure Foundry (and Responses) use AZURE_OPENAI_API_KEY so it does not conflict with OPENAI_API_KEY.\n if (prefix === \"azure-foundry\" || prefix === \"azure-foundry-responses\") {\n const fromEnv = readEnvKey(\"AZURE_OPENAI_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"AZURE_OPENAI_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"anthropic\") {\n const fromEnv = readEnvKey(\"ANTHROPIC_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"ANTHROPIC_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"openrouter\") {\n const fromEnv = readEnvKey(\"OPENROUTER_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"OPENROUTER_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"minimax\") {\n const fromEnv = readEnvKey(\"MINIMAX_API_KEY\");\n if (fromEnv) return { value: fromEnv, source: \"MINIMAX_API_KEY\" };\n return { source: \"none\" };\n }\n\n if (prefix === \"ollama\") {\n // Ollama's OpenAI-compatible endpoint accepts any non-empty string as the API key.\n return { value: \"ollama\", source: \"default\" };\n }\n\n // Generic env fallback: <PREFIX>_API_KEY (covers any provider following this convention).\n // NOTE: the gateway token is intentionally excluded — it is scoped to the local gateway\n // and must never be sent to arbitrary external endpoints.\n const fromGenericEnv = readEnvKey(`${prefix.toUpperCase()}_API_KEY`);\n if (fromGenericEnv) return { value: fromGenericEnv, source: `${prefix.toUpperCase()}_API_KEY` };\n\n return { source: \"none\" };\n}\n\n/**\n * Builds a multi-provider OpenAI-compatible proxy that routes each model to the correct provider API.\n * All existing call sites use `openai.chat.completions.create({ model, ... })` unchanged — this\n * proxy intercepts those calls and selects the right API endpoint + key based on the model prefix.\n *\n * Routing:\n * - `google/*` → Google Gemini OpenAI-compat endpoint (distill.apiKey or llm.providers.google.apiKey)\n * - `openai/*` or bare model (no `/`) → OpenAI (embedding.apiKey or llm.providers.openai.apiKey)\n * - `ollama/*` → local Ollama server (http://127.0.0.1:11434/v1, or llm.providers.ollama.baseURL)\n * - Other `provider/*` with explicit llm.providers config → custom endpoint\n * - Unknown provider, no config → throws UnconfiguredProviderError\n */\nexport function buildMultiProviderOpenAI(\n cfg: HybridMemoryConfig,\n api: ClawdbotPluginApi,\n costTracker: CostTracker | null,\n authBackoffStatePath?: string,\n): OpenAI {\n const clientCache = new Map<string, OpenAI>();\n /** Resolve env:VAR / file:/path / ${VAR} SecretRef strings so all llm.providers keys work with SecretRef format (Issue #344).\n * Delegates to the shared resolveSecretRef helper from config/parsers/core.ts to avoid duplicated logic. */\n const resolveApiKey = (key: string | undefined): string | undefined => {\n // Reject undefined, null, and whitespace-only strings before reaching resolveSecretRef (issues #10, #11).\n if (!key?.trim()) return undefined;\n return resolveSecretRef(key);\n };\n const { gatewayPortRaw, gatewayPort, gatewayAuthResolved, gatewayToken, gatewayBaseUrl } = extractGatewayConfig(cfg);\n // Fail closed: if gateway.auth.token is configured but cannot be resolved, throw rather than\n // silently falling back to OPENCLAW_GATEWAY_TOKEN — a stale env token would mask rollout mistakes.\n if (cfg.gateway?.auth?.token && !gatewayAuthResolved) {\n throw new Error(\n `memory-hybrid: gateway.auth.token is configured (SecretRef \"${cfg.gateway.auth.token}\") but could not be resolved. Ensure the referenced env var or file is accessible, or remove gateway.auth.token from the plugin config. Not falling back to OPENCLAW_GATEWAY_TOKEN to prevent silent auth misconfiguration.`,\n );\n }\n if (gatewayPortRaw && (!gatewayPort || gatewayPort < 1 || gatewayPort > 65535)) {\n api.logger.warn?.(\n `memory-hybrid: OPENCLAW_GATEWAY_PORT must be 1-65535 (got '${gatewayPortRaw}'); falling back to direct OpenAI.`,\n );\n }\n if (gatewayBaseUrl && !gatewayToken) {\n api.logger.warn?.(\n \"memory-hybrid: OPENCLAW_GATEWAY_PORT set but no gateway auth token found; set gateway.auth.token (SecretRef) in plugin config or OPENCLAW_GATEWAY_TOKEN env var. Gateway calls may fail if auth is required.\",\n );\n }\n\n function getOrCreate(key: string, factory: () => OpenAI): OpenAI {\n if (!clientCache.has(key)) clientCache.set(key, factory());\n return clientCache.get(key)!;\n }\n\n function defaultOpenAIClient(): OpenAI {\n if (gatewayBaseUrl) {\n const key = gatewayToken ?? cfg.embedding.apiKey;\n if (!key) throw new UnconfiguredProviderError(\"openai\", \"openai/*\");\n return getOrCreate(\n `openai:gateway:${gatewayBaseUrl}`,\n () =>\n new OpenAI({\n apiKey: key,\n baseURL: gatewayBaseUrl,\n }),\n );\n }\n if (!cfg.embedding.apiKey) throw new UnconfiguredProviderError(\"openai\", \"openai/*\");\n return getOrCreate(\"openai:default\", () => new OpenAI({ apiKey: cfg.embedding.apiKey! }));\n }\n\n /**\n * Normalize bare model names (no \"provider/\" prefix) to \"provider/model\" so the correct API is used.\n * OpenClaw and some configs use bare names (e.g. gemini-3.1-pro-preview); without the prefix we\n * would route to the default OpenAI client and get 404.\n */\n function normalizeModelId(model: string): string {\n const trimmed = model.trim();\n if (trimmed.includes(\"/\")) return trimmed;\n const lower = trimmed.toLowerCase();\n if (lower.startsWith(\"gemini-\")) return `google/${trimmed}`;\n if (lower.startsWith(\"claude-\")) return `anthropic/${trimmed}`;\n if (lower.startsWith(\"gpt-\") || /^o[0-9]+/.test(lower)) return `openai/${trimmed}`;\n if (lower.startsWith(\"minimax-\")) return `minimax/${canonicalizeMiniMaxModelId(trimmed)}`;\n return trimmed;\n }\n\n /**\n * Canonicalize model id for cost logging so pricing table lookup and reports use the correct provider.\n * Gateways may pass e.g. openai/gemini-3.1-pro-preview; we store google/gemini-3.1-pro-preview.\n */\n function canonicalModelIdForCost(providerSlashModel: string): string {\n const trimmed = providerSlashModel.trim();\n const slashIdx = trimmed.indexOf(\"/\");\n const bare = slashIdx >= 0 ? trimmed.slice(slashIdx + 1) : trimmed;\n const lower = bare.toLowerCase();\n if (lower.startsWith(\"gemini-\")) return `google/${bare}`;\n if (lower.startsWith(\"claude-\")) return `anthropic/${bare}`;\n if (lower.startsWith(\"gpt-\") || /^o[0-9]+/.test(lower)) return `openai/${bare}`;\n if (lower.startsWith(\"minimax-\")) return `minimax/${canonicalizeMiniMaxModelId(bare)}`;\n return trimmed.includes(\"/\") ? trimmed : `openai/${trimmed}`;\n }\n\n /** The configured auth.order map from plugin config (issue #311). */\n const authOrder = cfg.auth?.order;\n const preferOAuthWhenBoth = cfg.auth?.preferOAuthWhenBoth !== false;\n const failoverOpts = authBackoffStatePath\n ? {\n statePath: authBackoffStatePath,\n backoffScheduleMinutes: cfg.auth?.backoffScheduleMinutes?.length\n ? cfg.auth.backoffScheduleMinutes\n : DEFAULT_BACKOFF_MINUTES,\n resetBackoffAfterHours: cfg.auth?.resetBackoffAfterHours ?? DEFAULT_RESET_AFTER_HOURS,\n }\n : undefined;\n\n function hasApiKeyForProvider(prefix: string): boolean {\n const providerCfg: LLMProviderConfig | undefined = (\n cfg.llm?.providers as Record<string, LLMProviderConfig | undefined> | undefined\n )?.[prefix];\n const hasCustomExternalBaseURL =\n prefix === \"openai\" && Boolean(providerCfg?.baseURL && providerCfg.baseURL !== gatewayBaseUrl);\n // Exclude gatewayToken from the check for OAuth routing decisions — we only want to detect\n // a real direct API key (llm.providers.X.apiKey, embedding.apiKey, or env var).\n const { value } = resolveProviderApiKey(prefix, providerCfg, cfg, resolveApiKey, {\n gatewayToken: undefined,\n hasCustomExternalBaseURL,\n });\n return Boolean(value && value.length >= 10);\n }\n\n function resolveClient(model: string): {\n client: OpenAI;\n bareModel: string;\n ollamaBaseUrl?: string;\n useFullModel?: boolean;\n authType?: \"oauth\";\n } {\n const normalized = normalizeModelId(model);\n const trimmed = normalized.trim();\n const slashIdx = trimmed.indexOf(\"/\");\n\n if (slashIdx <= 0) {\n return { client: defaultOpenAIClient(), bareModel: trimmed };\n }\n\n const prefix = trimmed.slice(0, slashIdx).toLowerCase();\n const bareModel = trimmed.slice(slashIdx + 1);\n const providerCfg: LLMProviderConfig | undefined = (\n cfg.llm?.providers as Record<string, LLMProviderConfig | undefined> | undefined\n )?.[prefix];\n\n // OAuth + optional failover: when both OAuth and API key exist, prefer OAuth unless in backoff.\n if (hasOAuthProfiles(authOrder?.[prefix], prefix) && gatewayBaseUrl && gatewayToken) {\n const hasApi = hasApiKeyForProvider(prefix);\n const useOAuth = !hasApi || (preferOAuthWhenBoth && (!failoverOpts || !isOAuthInBackoff(prefix, failoverOpts)));\n if (useOAuth) {\n return {\n client: getOrCreate(\n `gateway:oauth:${gatewayBaseUrl}:${prefix}`,\n () => new OpenAI({ apiKey: gatewayToken, baseURL: gatewayBaseUrl }),\n ),\n bareModel,\n useFullModel: true,\n authType: \"oauth\",\n };\n }\n // Fall through to use API client (OAuth in backoff or preferOAuthWhenBoth false).\n }\n\n if (prefix === \"google\") {\n const { value: apiKey } = resolveProviderApiKey(\"google\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"google\", trimmed);\n const baseURL = providerCfg?.baseURL ?? GOOGLE_GEMINI_BASE_URL;\n return {\n client: getOrCreate(`google:${baseURL}`, () => new OpenAI({ apiKey, baseURL })),\n bareModel,\n };\n }\n\n if (prefix === \"openai\") {\n // Only use the gateway token when routing through the local gateway.\n // If a custom external baseURL is configured for the openai provider,\n // do NOT fall back to gatewayToken — that would send the internal gateway\n // token to an arbitrary external endpoint (security issue).\n const hasCustomExternalBaseURL = Boolean(providerCfg?.baseURL && providerCfg.baseURL !== gatewayBaseUrl);\n const { value: apiKey } = resolveProviderApiKey(\"openai\", providerCfg, cfg, resolveApiKey, {\n gatewayToken,\n hasCustomExternalBaseURL,\n });\n if (!apiKey) throw new UnconfiguredProviderError(\"openai\", trimmed);\n const baseURL = providerCfg?.baseURL ?? gatewayBaseUrl;\n const cacheKey = `openai:prefixed:${apiKey.slice(0, 8)}:${baseURL ?? \"default\"}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI({ apiKey, ...(baseURL ? { baseURL } : {}) })),\n bareModel,\n };\n }\n\n if (prefix === \"anthropic\") {\n const { value: apiKey } = resolveProviderApiKey(\"anthropic\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"anthropic\", trimmed);\n let baseURL = providerCfg?.baseURL ?? ANTHROPIC_BASE_URL;\n // Normalize: ensure Anthropic baseURL ends with /v1 for OpenAI-compatible chat endpoint (issue #950)\n baseURL = baseURL.replace(/\\/+$/, \"\");\n if (!baseURL.endsWith(\"/v1\")) {\n baseURL = `${baseURL}/v1`;\n }\n // Anthropic's OpenAI-compatible endpoints require anthropic-version header\n return {\n client: getOrCreate(\n `anthropic:${baseURL}`,\n () =>\n new OpenAI({\n apiKey,\n baseURL,\n defaultHeaders: { \"anthropic-version\": ANTHROPIC_VERSION_HEADER },\n }),\n ),\n bareModel,\n };\n }\n\n if (prefix === \"ollama\") {\n // Ollama exposes an OpenAI-compatible API at /v1. No real API key is required.\n let baseURL = providerCfg?.baseURL ?? `${OLLAMA_DEFAULT_BASE_URL}/v1`;\n // Ensure baseURL ends with /v1 for OpenAI client\n if (!/\\/v1\\/?$/.test(baseURL)) {\n baseURL = `${baseURL.replace(/\\/$/, \"\")}/v1`;\n }\n // Strip /v1 suffix for the health-check base URL\n const ollamaBaseUrl = baseURL.replace(/\\/v1\\/?$/, \"\");\n const { value: apiKey } = resolveProviderApiKey(\"ollama\", providerCfg, cfg, resolveApiKey);\n const cacheKey = `ollama:${baseURL}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI({ apiKey: apiKey ?? \"ollama\", baseURL })),\n bareModel,\n ollamaBaseUrl,\n };\n }\n\n if (prefix === \"openrouter\") {\n // OpenRouter exposes an OpenAI-compatible API at https://openrouter.ai/api/v1.\n // Model names are passed as-is after stripping the \"openrouter/\" prefix\n // (e.g. \"openrouter/anthropic/claude-3.5-sonnet\" → bareModel \"anthropic/claude-3.5-sonnet\").\n const { value: apiKey } = resolveProviderApiKey(\"openrouter\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"openrouter\", trimmed);\n const baseURL = providerCfg?.baseURL ?? OPENROUTER_BASE_URL;\n // Include apiKey prefix in cache key so key rotation takes effect without restart.\n // defaultHeaders follow OpenRouter's recommendations for attribution and rate-limit priority.\n const cacheKey = `openrouter:${baseURL}:${apiKey.slice(0, 8)}`;\n return {\n client: getOrCreate(\n cacheKey,\n () =>\n new OpenAI({\n apiKey,\n baseURL,\n defaultHeaders: {\n \"HTTP-Referer\": \"https://github.com/markus-lassfolk/openclaw-hybrid-memory\",\n \"X-Title\": \"openclaw-hybrid-memory\",\n },\n }),\n ),\n bareModel,\n };\n }\n\n if (prefix === \"minimax\") {\n // Use the built-in MiniMax API endpoint as default so callers never accidentally\n // fall through to the default OpenAI client (which returns 404 for MiniMax models).\n const { value: apiKey } = resolveProviderApiKey(\"minimax\", providerCfg, cfg, resolveApiKey);\n if (!apiKey) throw new UnconfiguredProviderError(\"minimax\", trimmed);\n const baseURL = providerCfg?.baseURL ?? MINIMAX_BASE_URL;\n // Canonicalize the bare model name: strip Ollama-style \":tag\" suffixes and fix casing\n // so that e.g. \"minimax-m2.5:cloud\" → \"MiniMax-M2.5\" (issue #400).\n const canonicalBareModel = canonicalizeMiniMaxModelId(bareModel);\n return {\n client: getOrCreate(`minimax:${baseURL}`, () => new OpenAI({ apiKey, baseURL })),\n bareModel: canonicalBareModel,\n };\n }\n\n // For all remaining providers (custom configs and unknown providers), use the centralised\n // resolver which covers llm.providers[prefix].apiKey and the <PREFIX>_API_KEY env convention.\n // The gateway token is intentionally excluded — it is scoped to the local gateway and must\n // never be sent to arbitrary external endpoints.\n const { value: resolvedApiKey } = resolveProviderApiKey(prefix, providerCfg, cfg, resolveApiKey);\n if (readProviderBaseUrl(providerCfg) || resolvedApiKey) {\n // apiKey may be absent when the provider only needs a custom baseURL (some self-hosted servers)\n const apiKey = resolvedApiKey ?? \"no-key\";\n const baseURL = readProviderBaseUrl(providerCfg);\n // Azure OpenAI / Foundry resource hosts: api-key header (SDK still adds Bearer; many endpoints accept both).\n const isAzureResource = typeof baseURL === \"string\" && isAzureOpenAiResourceEndpoint(baseURL);\n // Azure API Management (*.azure-api.net): must strip Bearer — use same fetch as embeddings factory.\n const isApim = typeof baseURL === \"string\" && isAzureApiManagementGatewayUrl(baseURL);\n const clientOpts: {\n apiKey: string;\n baseURL?: string;\n defaultHeaders?: Record<string, string>;\n fetch?: typeof globalThis.fetch;\n } = {\n apiKey,\n ...(baseURL ? { baseURL } : {}),\n };\n if (apiKey !== \"no-key\") {\n if (isAzureResource) clientOpts.defaultHeaders = { \"api-key\": apiKey };\n if (isApim) {\n clientOpts.defaultHeaders = { ...(clientOpts.defaultHeaders ?? {}), \"api-key\": apiKey };\n clientOpts.fetch = createApimGatewayFetch(apiKey);\n }\n }\n const cacheKey = `custom:${prefix}:${apiKey.slice(0, 8)}:${baseURL ?? \"default\"}`;\n return {\n client: getOrCreate(cacheKey, () => new OpenAI(clientOpts)),\n bareModel,\n };\n }\n\n // Unknown provider with no config — throw so callers can skip to the next model cleanly\n throw new UnconfiguredProviderError(prefix, trimmed);\n }\n\n /**\n * Newer OpenAI models (o-series, gpt-5+, gpt-4.1*) use `max_completion_tokens` instead of `max_tokens`.\n * Reasoning models (o1, o3, o4-*) and GPT-5 chat deployments (Azure) reject custom temperature/top_p — strip those params.\n * Applied for every routed provider (Azure Foundry, etc.), not only `openai/` — see model-capabilities.\n */\n function remapMaxTokensForOpenAI(body: Record<string, unknown>): Record<string, unknown> {\n let result = body;\n const modelId = String(result.model ?? \"\");\n if (requiresMaxCompletionTokens(modelId) && \"max_tokens\" in result && !(\"max_completion_tokens\" in result)) {\n const { max_tokens, ...rest } = result;\n result = { ...rest, max_completion_tokens: max_tokens };\n }\n if (shouldOmitSamplingParams(modelId)) {\n const { temperature, top_p, ...rest } = result as Record<string, unknown> & {\n temperature?: unknown;\n top_p?: unknown;\n };\n if (temperature !== undefined || top_p !== undefined) {\n api.logger.debug?.(`memory-hybrid: stripped temperature/top_p for model ${modelId}`);\n }\n result = rest;\n }\n return result;\n }\n\n /**\n * Shared cost-tracking wrapper for both chat and responses calls.\n * Fire-and-forget — never blocks or modifies the returned promise.\n */\n function trackCost(promise: Promise<unknown>, body: Record<string, unknown>, model: string, start: number): void {\n if (!costTracker) return;\n const feature = inferFeatureLabel(body, model);\n const normalizedModel = canonicalModelIdForCost(model.includes(\"/\") ? model : `openai/${model.trim()}`);\n void Promise.resolve(promise).then(\n (resp: unknown) => {\n try {\n const durationMs = Date.now() - start;\n const r = resp as {\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n input_tokens?: number;\n output_tokens?: number;\n };\n } | null;\n costTracker.record({\n feature,\n model: normalizedModel,\n inputTokens: r?.usage?.prompt_tokens ?? r?.usage?.input_tokens ?? 0,\n outputTokens: r?.usage?.completion_tokens ?? r?.usage?.output_tokens ?? 0,\n durationMs,\n success: true,\n });\n } catch {\n /* never let tracking break LLM calls */\n }\n },\n () => {\n try {\n const durationMs = Date.now() - start;\n const reqMessages = Array.isArray(body.messages) ? (body.messages as unknown[]) : [];\n const reqInput = Array.isArray(body.input) ? (body.input as unknown[]) : [];\n const content = reqMessages.length > 0 ? reqMessages : reqInput;\n const estimatedInputTokens = Math.ceil(JSON.stringify(content).length / 4);\n costTracker.record({\n feature,\n model: normalizedModel,\n inputTokens: estimatedInputTokens,\n outputTokens: 0,\n durationMs,\n success: false,\n });\n } catch {\n /* never let tracking break LLM calls */\n }\n },\n );\n }\n\n // Proxy that intercepts chat.completions.create and responses.create, routing to the right provider client.\n // All other OpenAI methods (embeddings, etc.) are NOT proxied — embeddings use a separate client.\n // The proxy base is only accessed for non-chat methods (not used by this plugin directly).\n // Only create it with a real key when one is available; otherwise omit to avoid \"unused\" placeholder.\n const proxyBaseKey = cfg.embedding.apiKey ?? gatewayToken ?? \"\";\n const proxyBase: OpenAI = proxyBaseKey ? new OpenAI({ apiKey: proxyBaseKey }) : ({} as OpenAI);\n return new Proxy(proxyBase, {\n get(target, prop, receiver) {\n if (prop === \"chat\") {\n return {\n completions: {\n create(\n body: Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0],\n opts?: Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[1],\n ) {\n const rawModel: string = (body as { model?: string }).model ?? \"\";\n const model = normalizeModelId(rawModel);\n const { client, bareModel, ollamaBaseUrl, useFullModel, authType } = resolveClient(model);\n const prefix = model.trim().split(\"/\")[0]?.toLowerCase();\n // When gateway-routed for non-OpenAI providers (auth.order OAuth), send the full \"provider/model\"\n // name so the gateway can route to the correct provider using the configured auth profile.\n const modelForRequest = useFullModel ? model.trim() : bareModel;\n const merged = { ...(body as object), model: modelForRequest } as Record<string, unknown>;\n const adjustedBody = remapMaxTokensForOpenAI(merged);\n const start = Date.now();\n\n // Responses-only models: route chat.completions.create → responses.create so direct SDK\n // call sites (classification, auto-classifier, etc.) work with azure-foundry-responses/* (#1043, Codex P1).\n if (resolveWireApi(model) === \"responses\") {\n if ((adjustedBody as { stream?: boolean }).stream) {\n return Promise.reject(\n new Error(\n \"memory-hybrid: stream=true is not supported for Responses API models (e.g. azure-foundry-responses/*); set stream: false.\",\n ),\n );\n }\n const responsesBody = buildResponsesRequestFromChatBody(adjustedBody);\n const input = responsesBody.input;\n if (!Array.isArray(input) || input.length === 0) {\n return Promise.reject(new Error(\"memory-hybrid: Responses API request requires non-empty messages\"));\n }\n const responsesNs = (\n client as unknown as { responses?: { create: (b: unknown, o?: unknown) => Promise<unknown> } }\n ).responses;\n if (!responsesNs?.create) {\n return Promise.reject(\n new Error(\n `Provider \"${prefix}\" does not expose responses.create(). Ensure the endpoint supports the OpenAI Responses API and the openai SDK is >=6.16.0.`,\n ),\n );\n }\n const modelLabel = String(adjustedBody.model ?? modelForRequest);\n let promise: Promise<unknown> = responsesNs.create(responsesBody, opts ?? {});\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n });\n }\n promise = promise.then((raw) => responsesRawToChatCompletion(raw as ResponsesApiResponse, modelLabel));\n trackCost(promise, body as unknown as Record<string, unknown>, model, start);\n return promise as ReturnType<OpenAI[\"chat\"][\"completions\"][\"create\"]>;\n }\n\n // For Ollama models, probe the local server before attempting the call so we fall\n // through to the next tier model quickly instead of waiting for a TCP timeout.\n const makeCall = () =>\n client.chat.completions.create(\n adjustedBody as unknown as Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0],\n opts,\n );\n let promise: ReturnType<typeof makeCall> = ollamaBaseUrl\n ? ((async () => {\n const available = await probeOllamaEndpoint(ollamaBaseUrl);\n if (!available) {\n const err = Object.assign(\n new Error(`Ollama not available at ${ollamaBaseUrl} (ECONNREFUSED) — try next model`),\n { code: \"ECONNREFUSED\" },\n );\n throw err;\n }\n return makeCall();\n })() as ReturnType<typeof makeCall>)\n : makeCall();\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n }) as ReturnType<typeof makeCall>;\n }\n trackCost(promise as Promise<unknown>, body as unknown as Record<string, unknown>, model, start);\n return promise;\n },\n },\n };\n }\n\n if (prop === \"responses\") {\n return {\n create(body: Record<string, unknown>, opts?: { signal?: AbortSignal }) {\n const rawModel: string = String(body.model ?? \"\");\n const model = normalizeModelId(rawModel);\n const { client, bareModel, useFullModel, authType } = resolveClient(model);\n const prefix = model.trim().split(\"/\")[0]?.toLowerCase();\n const modelForRequest = useFullModel ? model.trim() : bareModel;\n const merged = { ...body, model: modelForRequest };\n const adjustedBody = remapMaxTokensForOpenAI(merged);\n const start = Date.now();\n\n const responsesNs = (\n client as unknown as { responses?: { create: (b: unknown, o?: unknown) => Promise<unknown> } }\n ).responses;\n if (!responsesNs?.create) {\n return Promise.reject(\n new Error(\n `Provider \"${prefix}\" does not expose responses.create(). Ensure the endpoint supports the OpenAI Responses API and the openai SDK is >=6.16.0.`,\n ),\n );\n }\n\n let promise = responsesNs.create(adjustedBody, opts ?? {});\n if (authType === \"oauth\" && failoverOpts) {\n promise = promise.catch((err: unknown) => {\n recordOAuthFailure(prefix, failoverOpts);\n throw err;\n });\n }\n trackCost(promise, body, model, start);\n return promise;\n },\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n }) as OpenAI;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-context-engine.js","names":[],"sources":["../../setup/register-context-engine.ts"],"sourcesContent":["import type { PluginRuntime } from \"../api/plugin-runtime.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\n\ntype ContextEngineRegistrationRuntime = Pick<PluginRuntime, \"factsDb\" | \"vectorDb\" | \"wal\" | \"embeddings\" | \"cfg\">;\n\ntype ContextEngineRegistrar = (opts: {\n factsDb: ContextEngineRegistrationRuntime[\"factsDb\"];\n vectorDb: ContextEngineRegistrationRuntime[\"vectorDb\"];\n wal: ContextEngineRegistrationRuntime[\"wal\"];\n embeddings: ContextEngineRegistrationRuntime[\"embeddings\"];\n cfg: ContextEngineRegistrationRuntime[\"cfg\"];\n logger: { warn?: (message: string) => void };\n pluginVersion: string;\n}) => unknown;\n\ntype ContextEngineLoader = () => Promise<{\n registerHybridContextEngine: ContextEngineRegistrar;\n}>;\n\nexport function registerContextEngineBestEffort(args: {\n runtime: ContextEngineRegistrationRuntime;\n logger: { warn?: (message: string) => void };\n pluginVersion: string;\n loadContextEngine?: ContextEngineLoader;\n}): void {\n const { runtime, logger, pluginVersion } = args;\n const loadContextEngine = args.loadContextEngine ?? (() => import(\"../services/context-engine.js\"));\n\n void loadContextEngine()\n .then(({ registerHybridContextEngine }) =>\n registerHybridContextEngine({\n factsDb: runtime.factsDb,\n vectorDb: runtime.vectorDb,\n wal: runtime.wal,\n embeddings: runtime.embeddings,\n cfg: runtime.cfg,\n logger,\n pluginVersion,\n }),\n )\n .catch((err: unknown) => {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"plugin-register:context-engine\",\n });\n logger.warn?.(`memory-hybrid: ContextEngine registration skipped: ${err}`);\n });\n}\n"],"mappings":";;AAmBA,SAAgB,gCAAgC,MAKvC;CACP,MAAM,EAAE,SAAS,QAAQ,kBAAkB;CAG3C,CAF0B,KAAK,4BAA4B,OAAO,
|
|
1
|
+
{"version":3,"file":"register-context-engine.js","names":[],"sources":["../../setup/register-context-engine.ts"],"sourcesContent":["import type { PluginRuntime } from \"../api/plugin-runtime.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\n\ntype ContextEngineRegistrationRuntime = Pick<PluginRuntime, \"factsDb\" | \"vectorDb\" | \"wal\" | \"embeddings\" | \"cfg\">;\n\ntype ContextEngineRegistrar = (opts: {\n factsDb: ContextEngineRegistrationRuntime[\"factsDb\"];\n vectorDb: ContextEngineRegistrationRuntime[\"vectorDb\"];\n wal: ContextEngineRegistrationRuntime[\"wal\"];\n embeddings: ContextEngineRegistrationRuntime[\"embeddings\"];\n cfg: ContextEngineRegistrationRuntime[\"cfg\"];\n logger: { warn?: (message: string) => void };\n pluginVersion: string;\n}) => unknown;\n\ntype ContextEngineLoader = () => Promise<{\n registerHybridContextEngine: ContextEngineRegistrar;\n}>;\n\nexport function registerContextEngineBestEffort(args: {\n runtime: ContextEngineRegistrationRuntime;\n logger: { warn?: (message: string) => void };\n pluginVersion: string;\n loadContextEngine?: ContextEngineLoader;\n}): void {\n const { runtime, logger, pluginVersion } = args;\n const loadContextEngine = args.loadContextEngine ?? (() => import(\"../services/context-engine.js\"));\n\n void loadContextEngine()\n .then(({ registerHybridContextEngine }) =>\n registerHybridContextEngine({\n factsDb: runtime.factsDb,\n vectorDb: runtime.vectorDb,\n wal: runtime.wal,\n embeddings: runtime.embeddings,\n cfg: runtime.cfg,\n logger,\n pluginVersion,\n }),\n )\n .catch((err: unknown) => {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"plugin-register:context-engine\",\n });\n logger.warn?.(`memory-hybrid: ContextEngine registration skipped: ${err}`);\n });\n}\n"],"mappings":";;AAmBA,SAAgB,gCAAgC,MAKvC;CACP,MAAM,EAAE,SAAS,QAAQ,kBAAkB;CAG3C,CAF0B,KAAK,4BAA4B,OAAO,mCAE3C,EACpB,MAAM,EAAE,kCACP,4BAA4B;EAC1B,SAAS,QAAQ;EACjB,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,YAAY,QAAQ;EACpB,KAAK,QAAQ;EACb;EACA;CACF,CAAC,CACH,EACC,OAAO,QAAiB;EACvB,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,OAAO,OAAO,sDAAsD,KAAK;CAC3E,CAAC;AACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-hooks.js","names":[],"sources":["../../setup/register-hooks.ts"],"sourcesContent":["/**\n * Lifecycle Hooks Registration Wiring\n *\n * Registers lifecycle event hooks (before_agent_start, agent_end) with the OpenClaw API.\n * Extracted from index.ts to reduce main file size.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { MemoryPluginAPI } from \"../api/memory-plugin-api.js\";\nimport { resolveOpenclawJsonPathForWorkspace } from \"../cli/cmd-install.js\";\nimport { getMemoryCategories } from \"../config.js\";\nimport { withHookResolutionApi } from \"../lifecycle/hook-resolution-api.js\";\nimport { type LifecycleContext, createLifecycleHooks } from \"../lifecycle/hooks.js\";\nimport { resolveSessionKeyFromHookEvent } from \"../lifecycle/session-state.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildPostCompactionRecallSnippet } from \"../services/post-compaction-recall.js\";\nimport { runPreConsolidationFlush } from \"../services/pre-consolidation-flush.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { WorkflowTracker } from \"../services/workflow-tracker.js\";\nimport {\n buildUnsupportedPerAgentCompactionWarning,\n buildCompactionWatchdogAlert,\n buildCompactionModelWatchdogWarning,\n describeCompactionFallbackScope,\n resolveCompactionHookIdentity,\n resolveCompactionHookModelMetadata,\n resolveCompactionModelSelection,\n type CompactionWatchdogContext,\n} from \"../utils/compaction-model-watchdog.js\";\nimport {\n type MessageLike,\n sanitizeMessagesForClaude,\n sanitizeMessagesForOpenAIResponses,\n} from \"../utils/sanitize-messages.js\";\n\n/** Lifecycle hooks receive the stable plugin API (Phase 3). */\ntype HooksContext = MemoryPluginAPI;\n\n/** Issue #463: Returned handle for lifecycle hook cleanup. */\nexport interface LifecycleHooksHandle {\n /** Dispose all timers and clear per-session state (call on plugin stop). */\n dispose: () => void;\n}\n\nfunction emitCompactionModelWatchdogAlert(\n api: ClawdbotPluginApi,\n context: CompactionWatchdogContext,\n opts?: { event?: unknown; hookCtx?: unknown },\n): void {\n const configPath = resolveOpenclawJsonPathForWorkspace();\n let selectionUnknownReason: string | null = null;\n const identity = resolveCompactionHookIdentity(opts?.event, opts?.hookCtx, api.context);\n const scopeNote = describeCompactionFallbackScope(identity);\n let selection = resolveCompactionModelSelection(undefined, { fallbackPolicy: \"inherit-defaults-primary\" });\n if (!existsSync(configPath)) {\n selectionUnknownReason = `config file not found at ${configPath}`;\n } else {\n try {\n const root = JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>;\n selection = resolveCompactionModelSelection(root, { fallbackPolicy: \"inherit-defaults-primary\" });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n selectionUnknownReason = `failed reading ${configPath}: ${message}`;\n api.logger.debug?.(`memory-hybrid: ${context} watchdog — failed reading ${configPath}: ${err}; ${scopeNote}`);\n }\n }\n if (selectionUnknownReason) {\n api.logger.warn?.(\n `memory-hybrid: ${context} watchdog — compaction routing unknown (${selectionUnknownReason}); ${scopeNote}`,\n );\n return;\n }\n if (selection.routingUnknownFromConfig) {\n api.logger.warn?.(\n `memory-hybrid: ${context} watchdog — compaction routing unknown (neither agents.defaults.compaction.model nor agents.defaults.model.primary set; session chat model may apply); ${scopeNote}`,\n );\n return;\n }\n const unsupportedWarning = buildUnsupportedPerAgentCompactionWarning(selection, { context });\n if (unsupportedWarning) {\n api.logger.warn?.(`memory-hybrid: ${unsupportedWarning} ${scopeNote}`);\n }\n const warning = buildCompactionModelWatchdogWarning(selection, { context });\n if (warning) {\n api.logger.warn?.(`memory-hybrid: ${warning} ${scopeNote}`);\n } else {\n api.logger.debug?.(\n `memory-hybrid: ${context} watchdog — compaction model safe (provider=${selection.provider}, model=${selection.model}, reason=${selection.reason}); ${scopeNote}`,\n );\n }\n}\n\n/**\n * Register all lifecycle hooks with the OpenClaw API.\n * Creates and attaches before_agent_start and agent_end event handlers.\n * Returns a handle for cleanup (dispose).\n */\nexport function registerLifecycleHooks(ctx: HooksContext, api: ClawdbotPluginApi): LifecycleHooksHandle {\n let firstAgentEndCompactionCaptured = false;\n const registrationGeneration = ctx.registrationGeneration ?? -1;\n const currentRegistrationGenerationRef = ctx.currentRegistrationGenerationRef;\n if (!currentRegistrationGenerationRef) {\n api.logger.error?.(\n \"memory-hybrid: lifecycle generation ref missing; stale hooks will NOT be blocked on re-registration. This is a critical registration bug.\",\n );\n throw new Error(\"currentRegistrationGenerationRef is required for safe hook registration but was not provided\");\n }\n const effectiveRegistrationGenerationRef = currentRegistrationGenerationRef;\n const hookUnsubscribers: Array<() => void> = [];\n const trackUnsubscribe = (unsubscribe: unknown): void => {\n if (typeof unsubscribe === \"function\") {\n hookUnsubscribers.push(unsubscribe as () => void);\n }\n };\n const registerGuardedHook = (event: unknown, handler: unknown): void => {\n if (typeof handler !== \"function\") return;\n const guardedHandler = (...args: unknown[]): unknown => {\n if (effectiveRegistrationGenerationRef.value !== registrationGeneration) return undefined;\n return (handler as (...inner: unknown[]) => unknown)(...args);\n };\n const unsubscribe = (api.on as (eventName: unknown, callback: unknown) => unknown)(event, guardedHandler);\n trackUnsubscribe(unsubscribe);\n };\n const disposeRegisteredHooks = (): void => {\n const pendingUnsubscribers = [...hookUnsubscribers];\n hookUnsubscribers.length = 0;\n for (const unsubscribe of pendingUnsubscribers) {\n try {\n unsubscribe();\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:unsubscribe\",\n severity: \"warning\",\n });\n }\n }\n };\n const guardedApi = {\n ...api,\n on: ((event: unknown, handler: unknown) => registerGuardedHook(event, handler)) as ClawdbotPluginApi[\"on\"],\n } as ClawdbotPluginApi;\n let lifecycleContext: LifecycleContext;\n try {\n lifecycleContext = {\n factsDb: ctx.factsDb,\n edictStore: ctx.edictStore,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n embeddingRegistry: ctx.embeddingRegistry ?? null,\n openai: ctx.openai,\n cfg: ctx.cfg,\n credentialsDb: ctx.credentialsDb,\n aliasDb: ctx.aliasDb,\n wal: ctx.wal,\n eventLog: ctx.eventLog,\n narrativesDb: ctx.narrativesDb,\n workflowStore: ctx.workflowStore,\n // Issue #742: instantiate WorkflowTracker and wire into lifecycle so tool sequences\n // are recorded to workflow-traces.db (was implemented but never connected).\n workflowTracker:\n ctx.workflowStore && ctx.cfg.workflowTracking?.enabled\n ? new WorkflowTracker(ctx.workflowStore, ctx.cfg.workflowTracking)\n : undefined,\n currentAgentIdRef: ctx.currentAgentIdRef,\n lastProgressiveIndexIds: ctx.lastProgressiveIndexIds,\n restartPendingClearedRef: ctx.restartPendingClearedRef,\n resolvedSqlitePath: ctx.resolvedSqlitePath,\n walWrite: (operation, data, logger, supersedeTargetId) =>\n ctx.walWrite(ctx.wal, operation, data, logger, supersedeTargetId),\n walRemove: (id, logger) => ctx.walRemove(ctx.wal, id, logger),\n findSimilarByEmbedding: ctx.findSimilarByEmbedding,\n shouldCapture: ctx.shouldCapture,\n detectCategory: ctx.detectCategory,\n pendingLLMWarnings: ctx.pendingLLMWarnings,\n auditStore: ctx.auditStore ?? null,\n issueStore: ctx.issueStore,\n recallInFlightRef: ctx.recallInFlightRef,\n lastAutoRecallPromptRef: ctx.lastAutoRecallPromptRef,\n registrationGeneration,\n currentRegistrationGenerationRef,\n };\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:context\",\n });\n throw err;\n }\n\n let hooks;\n try {\n hooks = createLifecycleHooks(lifecycleContext);\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:create\",\n });\n throw err;\n }\n try {\n hooks.onAgentStart(guardedApi);\n hooks.onAgentEnd(guardedApi);\n hooks.onFrustrationDetect?.(guardedApi);\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:attach\",\n });\n disposeRegisteredHooks();\n hooks.dispose();\n throw err;\n }\n\n // Inject pending LLM config warnings into the agent's context once per occurrence.\n // Fires when all models in a tier fail due to missing provider API keys, so the AI\n // can relay the issue to the user in its response.\n guardedApi.on(\"before_prompt_build\", (): undefined | { prependContext: string } => {\n if (!ctx.pendingLLMWarnings) return;\n const warnings = ctx.pendingLLMWarnings.drain();\n if (warnings.length === 0) return;\n\n // Wrap warnings in a stable, parseable block to prevent prompt pollution\n const wrappedWarnings = [\n \"<llm-config-warning>\",\n ...warnings,\n \"Note: These configuration warnings will not repeat in this session.\",\n \"</llm-config-warning>\",\n ].join(\"\\n\");\n\n return { prependContext: wrappedWarnings };\n });\n\n // Temporary fix: ensure every tool_use has a tool_result immediately after (Claude API requirement).\n // Strip OpenAI Responses `reasoning` blocks (rs_*) so replay does not 400 (openclaw-maeve#23).\n // Mutates event.historyMessages in place so OpenClaw core uses the sanitized array.\n guardedApi.on(\"llm_input\", (ev: unknown) => {\n const event = ev as { historyMessages?: unknown[] };\n if (!event?.historyMessages || !Array.isArray(event.historyMessages)) return;\n let sanitized = sanitizeMessagesForClaude(event.historyMessages as MessageLike[]);\n sanitized = sanitizeMessagesForOpenAIResponses(sanitized);\n if (sanitized !== event.historyMessages) {\n event.historyMessages.length = 0;\n for (const m of sanitized) event.historyMessages.push(m);\n }\n });\n\n // Issue #274 — Static memory instructions via prependSystemContext / appendSystemContext\n //\n // SDK investigation (checked types/openclaw-plugin-sdk.d.ts and grep across the plugin):\n // - The current OpenClaw plugin SDK only exposes `prependContext` in the before_prompt_build\n // hook return type. Neither `prependSystemContext` nor `appendSystemContext` exist in the\n // SDK's ClawdbotPluginApi.on() handler signature.\n //\n // - TODO(#274): When the OpenClaw SDK adds `prependSystemContext` or `appendSystemContext`\n // to the before_prompt_build return type, switch this hook to return:\n // { appendSystemContext: staticMemoryInstructions }\n // This would enable Anthropic prompt-cache to cache the stable system suffix, saving\n // ~500-1000 tokens per turn. Until then, `prependContext` is the correct approach —\n // it is supported by all OpenClaw versions and produces the correct runtime behaviour.\n //\n // We ONLY inject when autoRecall is enabled — if the user opted out they don't want hints.\n // Silent mode suppresses capability hints (VerbosityLevel docs) regardless of explicit capabilityHints setting.\n const capabilityHintsMode = ctx.cfg.autoRecall.capabilityHints ?? \"off\";\n if (ctx.cfg.autoRecall.enabled && capabilityHintsMode !== \"off\" && ctx.cfg.verbosity !== \"silent\") {\n let staticMemoryInstructions: string | null = null;\n\n // Build once and cache — these never change within a gateway session.\n const buildStaticInstructions = (): string => {\n const cats = getMemoryCategories();\n const catList =\n cats.length > 0 ? cats.join(\", \") : \"preference, fact, decision, entity, pattern, rule, other, technical\";\n return [\n \"<!-- memory-hybrid: capability hints -->\",\n \"You have access to long-term memory tools for this session.\",\n `Available categories: ${catList}.`,\n \"Use memory_store to save important facts, preferences, and decisions.\",\n 'Use memory_recall(\"query\") or memory_recall(id: N) to retrieve specific memories.',\n \"Use memory_forget(memoryId) to remove stale or incorrect memories.\",\n \"Memories are scoped (global / user / agent / session) — prefer global unless scoped context is needed.\",\n \"<!-- /memory-hybrid: capability hints -->\",\n ].join(\"\\n\");\n };\n\n // Current SDKs only support `prependContext` for injecting additional context into\n // the prompt build. When a reliable capability signal for `appendSystemContext`\n // becomes available in the plugin SDK, this hook can be extended to prefer that\n // field without risking duplicate instructions.\n guardedApi.on(\"before_prompt_build\", (event: unknown, hookCtx: unknown): undefined | { prependContext: string } => {\n if (!staticMemoryInstructions) {\n staticMemoryInstructions = buildStaticInstructions();\n }\n if (capabilityHintsMode === \"session\") {\n const rApi = withHookResolutionApi(api, hookCtx);\n const sessionKey =\n resolveSessionKeyFromHookEvent(event, rApi) ?? lifecycleContext.currentAgentIdRef.value ?? \"default\";\n if (hooks.sessionState.capabilityHintsSessionsSeen.has(sessionKey)) return;\n hooks.sessionState.capabilityHintsSessionsSeen.add(sessionKey);\n hooks.sessionState.touchSession(sessionKey);\n hooks.sessionState.pruneSessionMaps();\n }\n return { prependContext: staticMemoryInstructions };\n });\n }\n\n // Issue #275 — Compaction Lifecycle Hooks\n //\n // Hook into before_compaction / after_compaction to:\n // before: flush WAL state, log pre-compaction snapshot\n // after: verify persistence, log compaction stats\n //\n // Feature detection: if the hook name is not recognised by this OpenClaw version\n // the api.on() call will silently no-op (unknown hooks are ignored by the registry).\n try {\n guardedApi.on(\"before_compaction\", async (event: unknown, hookCtx: unknown) => {\n const ev = event as {\n messageCount?: number;\n tokenCount?: number;\n compactingCount?: number;\n sessionFile?: string;\n };\n\n const hookModel = resolveCompactionHookModelMetadata(event, hookCtx);\n if (hookModel) {\n const alert = buildCompactionWatchdogAlert({\n stage: \"before_compaction\",\n model: hookModel.model,\n provider: hookModel.provider,\n source: hookModel.source,\n });\n if (alert) api.logger.warn?.(alert);\n } else {\n api.logger.debug?.(\n \"memory-hybrid: before_compaction watchdog — compaction provider/model metadata not exposed\",\n );\n emitCompactionModelWatchdogAlert(api, \"before_compaction\", { event, hookCtx });\n }\n\n await runPreConsolidationFlush(\n { wal: ctx.wal, factsDb: ctx.factsDb, vectorDb: ctx.vectorDb, embeddings: ctx.embeddings },\n api.logger,\n \"before_compaction\",\n );\n\n // Log pre-compaction snapshot for diagnostics\n const msgCount = ev.messageCount ?? 0;\n const tokenCount = ev.tokenCount ?? 0;\n api.logger.info?.(\n `memory-hybrid: before_compaction — messages=${msgCount} tokens≈${tokenCount} compacting=${ev.compactingCount ?? \"?\"}`,\n );\n if (!firstAgentEndCompactionCaptured) {\n firstAgentEndCompactionCaptured = true;\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"compaction\",\n operation: \"first-agent-end-compaction\",\n phase: \"startup.first-agent-end-compaction\",\n onceKey: \"startup.first-agent-end-compaction\",\n tags: {\n messageCount: msgCount,\n tokenCount,\n compactingCount: ev.compactingCount ?? \"unknown\",\n },\n });\n }\n\n let injectedContext = \"\";\n\n try {\n const fs = await import(\"node:fs\");\n if (typeof api.resolvePath === \"function\") {\n const agentsMdPath = api.resolvePath(\"AGENTS.md\");\n if (fs.existsSync(agentsMdPath)) {\n const content = fs.readFileSync(agentsMdPath, \"utf-8\");\n injectedContext += `\\n<!-- Workspace Agent Rules (AGENTS.md) -->\\n${content}\\n`;\n }\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: failed to read AGENTS.md for pre-compaction: ${err}`);\n }\n\n try {\n const scopeFilter = {\n sessionId: api.context?.sessionId,\n agentId: api.context?.agentId,\n userId: api.context?.userId,\n };\n const hotFacts = ctx.factsDb.getHotFacts(4000, scopeFilter);\n const pinnedRecallThreshold = ctx.cfg.autoRecall?.progressivePinnedRecallCount ?? 3;\n\n const pinnedFacts = hotFacts.filter(\n (x) => x.entry.decayClass === \"permanent\" || (x.entry.recallCount ?? 0) >= pinnedRecallThreshold,\n );\n\n if (pinnedFacts.length > 0) {\n injectedContext += \"\\n<!-- Pinned Session Constraints / Memories -->\\n\";\n injectedContext += `${pinnedFacts.map((f) => `- ${f.entry.summary || f.entry.text}`).join(\"\\n\")}\\n`;\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: failed to fetch pinned facts for pre-compaction: ${err}`);\n }\n\n if (injectedContext.trim().length > 0) {\n return {\n prependContext: `\\n=== CRITICAL CONSTRAINTS (DO NOT SUMMARISE AWAY) ===\\nThe following rules and pinned memories must be preserved and remain active in your ongoing context:\\n${injectedContext}====================================================\\n`,\n };\n }\n return undefined;\n });\n } catch (err) {\n // Older runtimes may throw on unknown hook names\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: \"register-before_compaction\",\n });\n api.logger.debug?.(`memory-hybrid: before_compaction hook not available (${err})`);\n }\n\n // Issue #966: Do not register `before_consolidation` — it is not in OpenClaw's PLUGIN_HOOK_NAMES (ignored + noisy).\n // WAL flush before compaction-style work is handled solely by `before_compaction` above (runPreConsolidationFlush).\n\n try {\n guardedApi.on(\n \"after_compaction\",\n async (event: unknown, hookCtx: unknown): Promise<undefined | { prependContext: string }> => {\n const ev = event as {\n messageCount?: number;\n tokenCount?: number;\n compactedCount?: number;\n sessionFile?: string;\n };\n\n const hookModel = resolveCompactionHookModelMetadata(event, hookCtx);\n if (hookModel) {\n const alert = buildCompactionWatchdogAlert({\n stage: \"after_compaction\",\n model: hookModel.model,\n provider: hookModel.provider,\n source: hookModel.source,\n });\n if (alert) api.logger.warn?.(alert);\n } else {\n api.logger.debug?.(\n \"memory-hybrid: after_compaction watchdog — compaction provider/model metadata not exposed\",\n );\n emitCompactionModelWatchdogAlert(api, \"after_compaction\", { event, hookCtx });\n }\n\n const msgCount = ev.messageCount ?? 0;\n const compacted = ev.compactedCount ?? 0;\n const tokenCount = ev.tokenCount ?? 0;\n\n api.logger.info?.(\n `memory-hybrid: after_compaction — messages=${msgCount} tokens≈${tokenCount} compacted=${compacted}`,\n );\n\n // Silent mode: skip memory summary injection entirely (no DB queries, no prependContext).\n if (ctx.cfg.verbosity === \"silent\") return;\n\n // Verify SQLite is still accessible after compaction\n let factCount = 0;\n try {\n factCount = ctx.factsDb.getCount();\n api.logger.debug?.(`memory-hybrid: after_compaction — SQLite health OK, ${factCount} facts in store`);\n } catch (dbErr) {\n api.logger.warn?.(\n `memory-hybrid: after_compaction — SQLite health check failed: ${dbErr}. Memory may be unavailable until restart.`,\n );\n // No summary injection if DB is unavailable\n return;\n }\n\n // Build post-compaction memory summary to help the agent resume with full context.\n // Inject the top-N most recent/important facts so the agent's first post-compaction\n // response references the right state.\n //\n // Issue #957: When auto-recall is on, re-run the recall pipeline against the last user\n // prompt (see lastAutoRecallPromptRef) so semantic/FTS matches are not lost after compaction.\n //\n // NOTE: `after_compaction` may not support prependContext in all OpenClaw versions.\n // The return value is a best-effort injection — older runtimes will silently ignore it.\n try {\n const blocks: string[] = [];\n\n if (ctx.cfg.autoRecall.enabled) {\n const lastPrompt = lifecycleContext.lastAutoRecallPromptRef.value;\n if (typeof lastPrompt === \"string\" && lastPrompt.trim().length >= 5) {\n const recallBlock = await buildPostCompactionRecallSnippet(lifecycleContext, api, lastPrompt);\n if (recallBlock) {\n blocks.push(recallBlock);\n api.logger.debug?.(\"memory-hybrid: after_compaction — injecting post-compaction recall snippet (#957)\");\n }\n }\n }\n\n const summaryFacts = ctx.factsDb.list(8);\n const summaryLines: string[] = [];\n\n if (summaryFacts.length > 0) {\n summaryLines.push(\"<!-- memory-hybrid: post-compaction memory summary -->\");\n summaryLines.push(\"Key memories retained across compaction:\");\n for (const f of summaryFacts) {\n const entityPrefix = f.entity ? `[${f.entity}] ` : \"\";\n const preview = f.text.length > 150 ? `${f.text.slice(0, 150)}…` : f.text;\n summaryLines.push(`- ${entityPrefix}${preview}`);\n }\n }\n\n // Append open issues summary if IssueStore is available\n if (ctx.issueStore) {\n try {\n const openIssues = ctx.issueStore.list({\n status: [\"open\", \"diagnosed\", \"fix-attempted\"],\n limit: 5,\n });\n if (openIssues.length > 0) {\n summaryLines.push(\"\");\n summaryLines.push(\"Open issues:\");\n for (const issue of openIssues) {\n summaryLines.push(`- [${issue.severity}] ${issue.title} (${issue.status})`);\n }\n }\n } catch {\n // Non-fatal\n }\n }\n\n if (summaryLines.length > 0) {\n summaryLines.push(\"<!-- /memory-hybrid: post-compaction memory summary -->\");\n blocks.push(summaryLines.join(\"\\n\"));\n }\n\n if (blocks.length > 0) {\n api.logger.debug?.(\n `memory-hybrid: after_compaction — injecting post-compaction context (${summaryFacts.length} summary facts)`,\n );\n return { prependContext: blocks.join(\"\\n\\n\") };\n }\n } catch {\n // Non-fatal — summary injection failure should not disrupt normal operation\n }\n },\n );\n } catch (err) {\n // Older runtimes may throw on unknown hook names\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: \"register-after_compaction\",\n });\n api.logger.debug?.(`memory-hybrid: after_compaction hook not available (${err})`);\n }\n\n // Update context refs from hooks (they may have been mutated)\n // Note: This is a workaround for the fact that the hooks need to update these values\n // but we can't easily pass them by reference in TypeScript without using objects.\n // The hooks update ctx.currentAgentId and ctx.lastProgressiveIndexIds internally.\n\n // Issue #463: Return handle for cleanup\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n disposeRegisteredHooks();\n hooks.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"register-hooks.js","names":[],"sources":["../../setup/register-hooks.ts"],"sourcesContent":["/**\n * Lifecycle Hooks Registration Wiring\n *\n * Registers lifecycle event hooks (before_agent_start, agent_end) with the OpenClaw API.\n * Extracted from index.ts to reduce main file size.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { MemoryPluginAPI } from \"../api/memory-plugin-api.js\";\nimport { resolveOpenclawJsonPathForWorkspace } from \"../cli/cmd-install.js\";\nimport { getMemoryCategories } from \"../config.js\";\nimport { withHookResolutionApi } from \"../lifecycle/hook-resolution-api.js\";\nimport { type LifecycleContext, createLifecycleHooks } from \"../lifecycle/hooks.js\";\nimport { resolveSessionKeyFromHookEvent } from \"../lifecycle/session-state.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { buildPostCompactionRecallSnippet } from \"../services/post-compaction-recall.js\";\nimport { runPreConsolidationFlush } from \"../services/pre-consolidation-flush.js\";\nimport { recordStartupMemoryCheckpoint } from \"../services/startup-memory-attribution.js\";\nimport { WorkflowTracker } from \"../services/workflow-tracker.js\";\nimport {\n buildUnsupportedPerAgentCompactionWarning,\n buildCompactionWatchdogAlert,\n buildCompactionModelWatchdogWarning,\n describeCompactionFallbackScope,\n resolveCompactionHookIdentity,\n resolveCompactionHookModelMetadata,\n resolveCompactionModelSelection,\n type CompactionWatchdogContext,\n} from \"../utils/compaction-model-watchdog.js\";\nimport {\n type MessageLike,\n sanitizeMessagesForClaude,\n sanitizeMessagesForOpenAIResponses,\n} from \"../utils/sanitize-messages.js\";\n\n/** Lifecycle hooks receive the stable plugin API (Phase 3). */\ntype HooksContext = MemoryPluginAPI;\n\n/** Issue #463: Returned handle for lifecycle hook cleanup. */\nexport interface LifecycleHooksHandle {\n /** Dispose all timers and clear per-session state (call on plugin stop). */\n dispose: () => void;\n}\n\nfunction emitCompactionModelWatchdogAlert(\n api: ClawdbotPluginApi,\n context: CompactionWatchdogContext,\n opts?: { event?: unknown; hookCtx?: unknown },\n): void {\n const configPath = resolveOpenclawJsonPathForWorkspace();\n let selectionUnknownReason: string | null = null;\n const identity = resolveCompactionHookIdentity(opts?.event, opts?.hookCtx, api.context);\n const scopeNote = describeCompactionFallbackScope(identity);\n let selection = resolveCompactionModelSelection(undefined, { fallbackPolicy: \"inherit-defaults-primary\" });\n if (!existsSync(configPath)) {\n selectionUnknownReason = `config file not found at ${configPath}`;\n } else {\n try {\n const root = JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>;\n selection = resolveCompactionModelSelection(root, { fallbackPolicy: \"inherit-defaults-primary\" });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n selectionUnknownReason = `failed reading ${configPath}: ${message}`;\n api.logger.debug?.(`memory-hybrid: ${context} watchdog — failed reading ${configPath}: ${err}; ${scopeNote}`);\n }\n }\n if (selectionUnknownReason) {\n api.logger.warn?.(\n `memory-hybrid: ${context} watchdog — compaction routing unknown (${selectionUnknownReason}); ${scopeNote}`,\n );\n return;\n }\n if (selection.routingUnknownFromConfig) {\n api.logger.warn?.(\n `memory-hybrid: ${context} watchdog — compaction routing unknown (neither agents.defaults.compaction.model nor agents.defaults.model.primary set; session chat model may apply); ${scopeNote}`,\n );\n return;\n }\n const unsupportedWarning = buildUnsupportedPerAgentCompactionWarning(selection, { context });\n if (unsupportedWarning) {\n api.logger.warn?.(`memory-hybrid: ${unsupportedWarning} ${scopeNote}`);\n }\n const warning = buildCompactionModelWatchdogWarning(selection, { context });\n if (warning) {\n api.logger.warn?.(`memory-hybrid: ${warning} ${scopeNote}`);\n } else {\n api.logger.debug?.(\n `memory-hybrid: ${context} watchdog — compaction model safe (provider=${selection.provider}, model=${selection.model}, reason=${selection.reason}); ${scopeNote}`,\n );\n }\n}\n\n/**\n * Register all lifecycle hooks with the OpenClaw API.\n * Creates and attaches before_agent_start and agent_end event handlers.\n * Returns a handle for cleanup (dispose).\n */\nexport function registerLifecycleHooks(ctx: HooksContext, api: ClawdbotPluginApi): LifecycleHooksHandle {\n let firstAgentEndCompactionCaptured = false;\n const registrationGeneration = ctx.registrationGeneration ?? -1;\n const currentRegistrationGenerationRef = ctx.currentRegistrationGenerationRef;\n if (!currentRegistrationGenerationRef) {\n api.logger.error?.(\n \"memory-hybrid: lifecycle generation ref missing; stale hooks will NOT be blocked on re-registration. This is a critical registration bug.\",\n );\n throw new Error(\"currentRegistrationGenerationRef is required for safe hook registration but was not provided\");\n }\n const effectiveRegistrationGenerationRef = currentRegistrationGenerationRef;\n const hookUnsubscribers: Array<() => void> = [];\n const trackUnsubscribe = (unsubscribe: unknown): void => {\n if (typeof unsubscribe === \"function\") {\n hookUnsubscribers.push(unsubscribe as () => void);\n }\n };\n const registerGuardedHook = (event: unknown, handler: unknown): void => {\n if (typeof handler !== \"function\") return;\n const guardedHandler = (...args: unknown[]): unknown => {\n if (effectiveRegistrationGenerationRef.value !== registrationGeneration) return undefined;\n return (handler as (...inner: unknown[]) => unknown)(...args);\n };\n const unsubscribe = (api.on as (eventName: unknown, callback: unknown) => unknown)(event, guardedHandler);\n trackUnsubscribe(unsubscribe);\n };\n const disposeRegisteredHooks = (): void => {\n const pendingUnsubscribers = [...hookUnsubscribers];\n hookUnsubscribers.length = 0;\n for (const unsubscribe of pendingUnsubscribers) {\n try {\n unsubscribe();\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:unsubscribe\",\n severity: \"warning\",\n });\n }\n }\n };\n const guardedApi = {\n ...api,\n on: ((event: unknown, handler: unknown) => registerGuardedHook(event, handler)) as ClawdbotPluginApi[\"on\"],\n } as ClawdbotPluginApi;\n let lifecycleContext: LifecycleContext;\n try {\n lifecycleContext = {\n factsDb: ctx.factsDb,\n edictStore: ctx.edictStore,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n embeddingRegistry: ctx.embeddingRegistry ?? null,\n openai: ctx.openai,\n cfg: ctx.cfg,\n credentialsDb: ctx.credentialsDb,\n aliasDb: ctx.aliasDb,\n wal: ctx.wal,\n eventLog: ctx.eventLog,\n narrativesDb: ctx.narrativesDb,\n workflowStore: ctx.workflowStore,\n // Issue #742: instantiate WorkflowTracker and wire into lifecycle so tool sequences\n // are recorded to workflow-traces.db (was implemented but never connected).\n workflowTracker:\n ctx.workflowStore && ctx.cfg.workflowTracking?.enabled\n ? new WorkflowTracker(ctx.workflowStore, ctx.cfg.workflowTracking)\n : undefined,\n currentAgentIdRef: ctx.currentAgentIdRef,\n lastProgressiveIndexIds: ctx.lastProgressiveIndexIds,\n restartPendingClearedRef: ctx.restartPendingClearedRef,\n resolvedSqlitePath: ctx.resolvedSqlitePath,\n walWrite: (operation, data, logger, supersedeTargetId) =>\n ctx.walWrite(ctx.wal, operation, data, logger, supersedeTargetId),\n walRemove: (id, logger) => ctx.walRemove(ctx.wal, id, logger),\n findSimilarByEmbedding: ctx.findSimilarByEmbedding,\n shouldCapture: ctx.shouldCapture,\n detectCategory: ctx.detectCategory,\n pendingLLMWarnings: ctx.pendingLLMWarnings,\n auditStore: ctx.auditStore ?? null,\n issueStore: ctx.issueStore,\n recallInFlightRef: ctx.recallInFlightRef,\n lastAutoRecallPromptRef: ctx.lastAutoRecallPromptRef,\n registrationGeneration,\n currentRegistrationGenerationRef,\n };\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:context\",\n });\n throw err;\n }\n\n let hooks;\n try {\n hooks = createLifecycleHooks(lifecycleContext);\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:create\",\n });\n throw err;\n }\n try {\n hooks.onAgentStart(guardedApi);\n hooks.onAgentEnd(guardedApi);\n hooks.onFrustrationDetect?.(guardedApi);\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"registration\",\n operation: \"register-hooks:attach\",\n });\n disposeRegisteredHooks();\n hooks.dispose();\n throw err;\n }\n\n // Inject pending LLM config warnings into the agent's context once per occurrence.\n // Fires when all models in a tier fail due to missing provider API keys, so the AI\n // can relay the issue to the user in its response.\n guardedApi.on(\"before_prompt_build\", (): undefined | { prependContext: string } => {\n if (!ctx.pendingLLMWarnings) return;\n const warnings = ctx.pendingLLMWarnings.drain();\n if (warnings.length === 0) return;\n\n // Wrap warnings in a stable, parseable block to prevent prompt pollution\n const wrappedWarnings = [\n \"<llm-config-warning>\",\n ...warnings,\n \"Note: These configuration warnings will not repeat in this session.\",\n \"</llm-config-warning>\",\n ].join(\"\\n\");\n\n return { prependContext: wrappedWarnings };\n });\n\n // Temporary fix: ensure every tool_use has a tool_result immediately after (Claude API requirement).\n // Strip OpenAI Responses `reasoning` blocks (rs_*) so replay does not 400 (openclaw-maeve#23).\n // Mutates event.historyMessages in place so OpenClaw core uses the sanitized array.\n guardedApi.on(\"llm_input\", (ev: unknown) => {\n const event = ev as { historyMessages?: unknown[] };\n if (!event?.historyMessages || !Array.isArray(event.historyMessages)) return;\n let sanitized = sanitizeMessagesForClaude(event.historyMessages as MessageLike[]);\n sanitized = sanitizeMessagesForOpenAIResponses(sanitized);\n if (sanitized !== event.historyMessages) {\n event.historyMessages.length = 0;\n for (const m of sanitized) event.historyMessages.push(m);\n }\n });\n\n // Issue #274 — Static memory instructions via prependSystemContext / appendSystemContext\n //\n // SDK investigation (checked types/openclaw-plugin-sdk.d.ts and grep across the plugin):\n // - The current OpenClaw plugin SDK only exposes `prependContext` in the before_prompt_build\n // hook return type. Neither `prependSystemContext` nor `appendSystemContext` exist in the\n // SDK's ClawdbotPluginApi.on() handler signature.\n //\n // - TODO(#274): When the OpenClaw SDK adds `prependSystemContext` or `appendSystemContext`\n // to the before_prompt_build return type, switch this hook to return:\n // { appendSystemContext: staticMemoryInstructions }\n // This would enable Anthropic prompt-cache to cache the stable system suffix, saving\n // ~500-1000 tokens per turn. Until then, `prependContext` is the correct approach —\n // it is supported by all OpenClaw versions and produces the correct runtime behaviour.\n //\n // We ONLY inject when autoRecall is enabled — if the user opted out they don't want hints.\n // Silent mode suppresses capability hints (VerbosityLevel docs) regardless of explicit capabilityHints setting.\n const capabilityHintsMode = ctx.cfg.autoRecall.capabilityHints ?? \"off\";\n if (ctx.cfg.autoRecall.enabled && capabilityHintsMode !== \"off\" && ctx.cfg.verbosity !== \"silent\") {\n let staticMemoryInstructions: string | null = null;\n\n // Build once and cache — these never change within a gateway session.\n const buildStaticInstructions = (): string => {\n const cats = getMemoryCategories();\n const catList =\n cats.length > 0 ? cats.join(\", \") : \"preference, fact, decision, entity, pattern, rule, other, technical\";\n return [\n \"<!-- memory-hybrid: capability hints -->\",\n \"You have access to long-term memory tools for this session.\",\n `Available categories: ${catList}.`,\n \"Use memory_store to save important facts, preferences, and decisions.\",\n 'Use memory_recall(\"query\") or memory_recall(id: N) to retrieve specific memories.',\n \"Use memory_forget(memoryId) to remove stale or incorrect memories.\",\n \"Memories are scoped (global / user / agent / session) — prefer global unless scoped context is needed.\",\n \"<!-- /memory-hybrid: capability hints -->\",\n ].join(\"\\n\");\n };\n\n // Current SDKs only support `prependContext` for injecting additional context into\n // the prompt build. When a reliable capability signal for `appendSystemContext`\n // becomes available in the plugin SDK, this hook can be extended to prefer that\n // field without risking duplicate instructions.\n guardedApi.on(\"before_prompt_build\", (event: unknown, hookCtx: unknown): undefined | { prependContext: string } => {\n if (!staticMemoryInstructions) {\n staticMemoryInstructions = buildStaticInstructions();\n }\n if (capabilityHintsMode === \"session\") {\n const rApi = withHookResolutionApi(api, hookCtx);\n const sessionKey =\n resolveSessionKeyFromHookEvent(event, rApi) ?? lifecycleContext.currentAgentIdRef.value ?? \"default\";\n if (hooks.sessionState.capabilityHintsSessionsSeen.has(sessionKey)) return;\n hooks.sessionState.capabilityHintsSessionsSeen.add(sessionKey);\n hooks.sessionState.touchSession(sessionKey);\n hooks.sessionState.pruneSessionMaps();\n }\n return { prependContext: staticMemoryInstructions };\n });\n }\n\n // Issue #275 — Compaction Lifecycle Hooks\n //\n // Hook into before_compaction / after_compaction to:\n // before: flush WAL state, log pre-compaction snapshot\n // after: verify persistence, log compaction stats\n //\n // Feature detection: if the hook name is not recognised by this OpenClaw version\n // the api.on() call will silently no-op (unknown hooks are ignored by the registry).\n try {\n guardedApi.on(\"before_compaction\", async (event: unknown, hookCtx: unknown) => {\n const ev = event as {\n messageCount?: number;\n tokenCount?: number;\n compactingCount?: number;\n sessionFile?: string;\n };\n\n const hookModel = resolveCompactionHookModelMetadata(event, hookCtx);\n if (hookModel) {\n const alert = buildCompactionWatchdogAlert({\n stage: \"before_compaction\",\n model: hookModel.model,\n provider: hookModel.provider,\n source: hookModel.source,\n });\n if (alert) api.logger.warn?.(alert);\n } else {\n api.logger.debug?.(\n \"memory-hybrid: before_compaction watchdog — compaction provider/model metadata not exposed\",\n );\n emitCompactionModelWatchdogAlert(api, \"before_compaction\", { event, hookCtx });\n }\n\n await runPreConsolidationFlush(\n { wal: ctx.wal, factsDb: ctx.factsDb, vectorDb: ctx.vectorDb, embeddings: ctx.embeddings },\n api.logger,\n \"before_compaction\",\n );\n\n // Log pre-compaction snapshot for diagnostics\n const msgCount = ev.messageCount ?? 0;\n const tokenCount = ev.tokenCount ?? 0;\n api.logger.info?.(\n `memory-hybrid: before_compaction — messages=${msgCount} tokens≈${tokenCount} compacting=${ev.compactingCount ?? \"?\"}`,\n );\n if (!firstAgentEndCompactionCaptured) {\n firstAgentEndCompactionCaptured = true;\n recordStartupMemoryCheckpoint({\n logger: api.logger,\n subsystem: \"compaction\",\n operation: \"first-agent-end-compaction\",\n phase: \"startup.first-agent-end-compaction\",\n onceKey: \"startup.first-agent-end-compaction\",\n tags: {\n messageCount: msgCount,\n tokenCount,\n compactingCount: ev.compactingCount ?? \"unknown\",\n },\n });\n }\n\n let injectedContext = \"\";\n\n try {\n const fs = await import(\"node:fs\");\n if (typeof api.resolvePath === \"function\") {\n const agentsMdPath = api.resolvePath(\"AGENTS.md\");\n if (fs.existsSync(agentsMdPath)) {\n const content = fs.readFileSync(agentsMdPath, \"utf-8\");\n injectedContext += `\\n<!-- Workspace Agent Rules (AGENTS.md) -->\\n${content}\\n`;\n }\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: failed to read AGENTS.md for pre-compaction: ${err}`);\n }\n\n try {\n const scopeFilter = {\n sessionId: api.context?.sessionId,\n agentId: api.context?.agentId,\n userId: api.context?.userId,\n };\n const hotFacts = ctx.factsDb.getHotFacts(4000, scopeFilter);\n const pinnedRecallThreshold = ctx.cfg.autoRecall?.progressivePinnedRecallCount ?? 3;\n\n const pinnedFacts = hotFacts.filter(\n (x) => x.entry.decayClass === \"permanent\" || (x.entry.recallCount ?? 0) >= pinnedRecallThreshold,\n );\n\n if (pinnedFacts.length > 0) {\n injectedContext += \"\\n<!-- Pinned Session Constraints / Memories -->\\n\";\n injectedContext += `${pinnedFacts.map((f) => `- ${f.entry.summary || f.entry.text}`).join(\"\\n\")}\\n`;\n }\n } catch (err) {\n api.logger.debug?.(`memory-hybrid: failed to fetch pinned facts for pre-compaction: ${err}`);\n }\n\n if (injectedContext.trim().length > 0) {\n return {\n prependContext: `\\n=== CRITICAL CONSTRAINTS (DO NOT SUMMARISE AWAY) ===\\nThe following rules and pinned memories must be preserved and remain active in your ongoing context:\\n${injectedContext}====================================================\\n`,\n };\n }\n return undefined;\n });\n } catch (err) {\n // Older runtimes may throw on unknown hook names\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: \"register-before_compaction\",\n });\n api.logger.debug?.(`memory-hybrid: before_compaction hook not available (${err})`);\n }\n\n // Issue #966: Do not register `before_consolidation` — it is not in OpenClaw's PLUGIN_HOOK_NAMES (ignored + noisy).\n // WAL flush before compaction-style work is handled solely by `before_compaction` above (runPreConsolidationFlush).\n\n try {\n guardedApi.on(\n \"after_compaction\",\n async (event: unknown, hookCtx: unknown): Promise<undefined | { prependContext: string }> => {\n const ev = event as {\n messageCount?: number;\n tokenCount?: number;\n compactedCount?: number;\n sessionFile?: string;\n };\n\n const hookModel = resolveCompactionHookModelMetadata(event, hookCtx);\n if (hookModel) {\n const alert = buildCompactionWatchdogAlert({\n stage: \"after_compaction\",\n model: hookModel.model,\n provider: hookModel.provider,\n source: hookModel.source,\n });\n if (alert) api.logger.warn?.(alert);\n } else {\n api.logger.debug?.(\n \"memory-hybrid: after_compaction watchdog — compaction provider/model metadata not exposed\",\n );\n emitCompactionModelWatchdogAlert(api, \"after_compaction\", { event, hookCtx });\n }\n\n const msgCount = ev.messageCount ?? 0;\n const compacted = ev.compactedCount ?? 0;\n const tokenCount = ev.tokenCount ?? 0;\n\n api.logger.info?.(\n `memory-hybrid: after_compaction — messages=${msgCount} tokens≈${tokenCount} compacted=${compacted}`,\n );\n\n // Silent mode: skip memory summary injection entirely (no DB queries, no prependContext).\n if (ctx.cfg.verbosity === \"silent\") return;\n\n // Verify SQLite is still accessible after compaction\n let factCount = 0;\n try {\n factCount = ctx.factsDb.getCount();\n api.logger.debug?.(`memory-hybrid: after_compaction — SQLite health OK, ${factCount} facts in store`);\n } catch (dbErr) {\n api.logger.warn?.(\n `memory-hybrid: after_compaction — SQLite health check failed: ${dbErr}. Memory may be unavailable until restart.`,\n );\n // No summary injection if DB is unavailable\n return;\n }\n\n // Build post-compaction memory summary to help the agent resume with full context.\n // Inject the top-N most recent/important facts so the agent's first post-compaction\n // response references the right state.\n //\n // Issue #957: When auto-recall is on, re-run the recall pipeline against the last user\n // prompt (see lastAutoRecallPromptRef) so semantic/FTS matches are not lost after compaction.\n //\n // NOTE: `after_compaction` may not support prependContext in all OpenClaw versions.\n // The return value is a best-effort injection — older runtimes will silently ignore it.\n try {\n const blocks: string[] = [];\n\n if (ctx.cfg.autoRecall.enabled) {\n const lastPrompt = lifecycleContext.lastAutoRecallPromptRef.value;\n if (typeof lastPrompt === \"string\" && lastPrompt.trim().length >= 5) {\n const recallBlock = await buildPostCompactionRecallSnippet(lifecycleContext, api, lastPrompt);\n if (recallBlock) {\n blocks.push(recallBlock);\n api.logger.debug?.(\"memory-hybrid: after_compaction — injecting post-compaction recall snippet (#957)\");\n }\n }\n }\n\n const summaryFacts = ctx.factsDb.list(8);\n const summaryLines: string[] = [];\n\n if (summaryFacts.length > 0) {\n summaryLines.push(\"<!-- memory-hybrid: post-compaction memory summary -->\");\n summaryLines.push(\"Key memories retained across compaction:\");\n for (const f of summaryFacts) {\n const entityPrefix = f.entity ? `[${f.entity}] ` : \"\";\n const preview = f.text.length > 150 ? `${f.text.slice(0, 150)}…` : f.text;\n summaryLines.push(`- ${entityPrefix}${preview}`);\n }\n }\n\n // Append open issues summary if IssueStore is available\n if (ctx.issueStore) {\n try {\n const openIssues = ctx.issueStore.list({\n status: [\"open\", \"diagnosed\", \"fix-attempted\"],\n limit: 5,\n });\n if (openIssues.length > 0) {\n summaryLines.push(\"\");\n summaryLines.push(\"Open issues:\");\n for (const issue of openIssues) {\n summaryLines.push(`- [${issue.severity}] ${issue.title} (${issue.status})`);\n }\n }\n } catch {\n // Non-fatal\n }\n }\n\n if (summaryLines.length > 0) {\n summaryLines.push(\"<!-- /memory-hybrid: post-compaction memory summary -->\");\n blocks.push(summaryLines.join(\"\\n\"));\n }\n\n if (blocks.length > 0) {\n api.logger.debug?.(\n `memory-hybrid: after_compaction — injecting post-compaction context (${summaryFacts.length} summary facts)`,\n );\n return { prependContext: blocks.join(\"\\n\\n\") };\n }\n } catch {\n // Non-fatal — summary injection failure should not disrupt normal operation\n }\n },\n );\n } catch (err) {\n // Older runtimes may throw on unknown hook names\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: \"register-after_compaction\",\n });\n api.logger.debug?.(`memory-hybrid: after_compaction hook not available (${err})`);\n }\n\n // Update context refs from hooks (they may have been mutated)\n // Note: This is a workaround for the fact that the hooks need to update these values\n // but we can't easily pass them by reference in TypeScript without using objects.\n // The hooks update ctx.currentAgentId and ctx.lastProgressiveIndexIds internally.\n\n // Issue #463: Return handle for cleanup\n let disposed = false;\n return {\n dispose: () => {\n if (disposed) return;\n disposed = true;\n disposeRegisteredHooks();\n hooks.dispose();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA6CA,SAAS,iCACP,KACA,SACA,MACM;CACN,MAAM,aAAa,oCAAoC;CACvD,IAAI,yBAAwC;CAE5C,MAAM,YAAY,gCADD,8BAA8B,MAAM,OAAO,MAAM,SAAS,IAAI,OACtB,CAAC;CAC1D,IAAI,YAAY,gCAAgC,KAAA,GAAW,EAAE,gBAAgB,2BAA2B,CAAC;CACzG,IAAI,CAAC,WAAW,UAAU,GACxB,yBAAyB,4BAA4B;MAErD,IAAI;EAEF,YAAY,gCADC,KAAK,MAAM,aAAa,YAAY,OAAO,CACT,GAAG,EAAE,gBAAgB,2BAA2B,CAAC;CAClG,SAAS,KAAK;EAEZ,yBAAyB,kBAAkB,WAAW,IADtC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAE/D,IAAI,OAAO,QAAQ,kBAAkB,QAAQ,6BAA6B,WAAW,IAAI,IAAI,IAAI,WAAW;CAC9G;CAEF,IAAI,wBAAwB;EAC1B,IAAI,OAAO,OACT,kBAAkB,QAAQ,0CAA0C,uBAAuB,KAAK,WAClG;EACA;CACF;CACA,IAAI,UAAU,0BAA0B;EACtC,IAAI,OAAO,OACT,kBAAkB,QAAQ,yJAAyJ,WACrL;EACA;CACF;CACA,MAAM,qBAAqB,0CAA0C,WAAW,EAAE,QAAQ,CAAC;CAC3F,IAAI,oBACF,IAAI,OAAO,OAAO,kBAAkB,mBAAmB,GAAG,WAAW;CAEvE,MAAM,UAAU,oCAAoC,WAAW,EAAE,QAAQ,CAAC;CAC1E,IAAI,SACF,IAAI,OAAO,OAAO,kBAAkB,QAAQ,GAAG,WAAW;MAE1D,IAAI,OAAO,QACT,kBAAkB,QAAQ,8CAA8C,UAAU,SAAS,UAAU,UAAU,MAAM,WAAW,UAAU,OAAO,KAAK,WACxJ;AAEJ;;;;;;AAOA,SAAgB,uBAAuB,KAAmB,KAA8C;CACtG,IAAI,kCAAkC;CACtC,MAAM,yBAAyB,IAAI,0BAA0B;CAC7D,MAAM,mCAAmC,IAAI;CAC7C,IAAI,CAAC,kCAAkC;EACrC,IAAI,OAAO,QACT,2IACF;EACA,MAAM,IAAI,MAAM,8FAA8F;CAChH;CACA,MAAM,qCAAqC;CAC3C,MAAM,oBAAuC,CAAC;CAC9C,MAAM,oBAAoB,gBAA+B;EACvD,IAAI,OAAO,gBAAgB,YACzB,kBAAkB,KAAK,WAAyB;CAEpD;CACA,MAAM,uBAAuB,OAAgB,YAA2B;EACtE,IAAI,OAAO,YAAY,YAAY;EACnC,MAAM,kBAAkB,GAAG,SAA6B;GACtD,IAAI,mCAAmC,UAAU,wBAAwB,OAAO,KAAA;GAChF,OAAQ,QAA6C,GAAG,IAAI;EAC9D;EAEA,iBADqB,IAAI,GAA0D,OAAO,cAC/D,CAAC;CAC9B;CACA,MAAM,+BAAqC;EACzC,MAAM,uBAAuB,CAAC,GAAG,iBAAiB;EAClD,kBAAkB,SAAS;EAC3B,KAAK,MAAM,eAAe,sBACxB,IAAI;GACF,YAAY;EACd,SAAS,KAAK;GACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;IACtE,WAAW;IACX,WAAW;IACX,UAAU;GACZ,CAAC;EACH;CAEJ;CACA,MAAM,aAAa;EACjB,GAAG;EACH,MAAM,OAAgB,YAAqB,oBAAoB,OAAO,OAAO;CAC/E;CACA,IAAI;CACJ,IAAI;EACF,mBAAmB;GACjB,SAAS,IAAI;GACb,YAAY,IAAI;GAChB,UAAU,IAAI;GACd,YAAY,IAAI;GAChB,mBAAmB,IAAI,qBAAqB;GAC5C,QAAQ,IAAI;GACZ,KAAK,IAAI;GACT,eAAe,IAAI;GACnB,SAAS,IAAI;GACb,KAAK,IAAI;GACT,UAAU,IAAI;GACd,cAAc,IAAI;GAClB,eAAe,IAAI;GAGnB,iBACE,IAAI,iBAAiB,IAAI,IAAI,kBAAkB,UAC3C,IAAI,gBAAgB,IAAI,eAAe,IAAI,IAAI,gBAAgB,IAC/D,KAAA;GACN,mBAAmB,IAAI;GACvB,yBAAyB,IAAI;GAC7B,0BAA0B,IAAI;GAC9B,oBAAoB,IAAI;GACxB,WAAW,WAAW,MAAM,QAAQ,sBAClC,IAAI,SAAS,IAAI,KAAK,WAAW,MAAM,QAAQ,iBAAiB;GAClE,YAAY,IAAI,WAAW,IAAI,UAAU,IAAI,KAAK,IAAI,MAAM;GAC5D,wBAAwB,IAAI;GAC5B,eAAe,IAAI;GACnB,gBAAgB,IAAI;GACpB,oBAAoB,IAAI;GACxB,YAAY,IAAI,cAAc;GAC9B,YAAY,IAAI;GAChB,mBAAmB,IAAI;GACvB,yBAAyB,IAAI;GAC7B;GACA;EACF;CACF,SAAS,KAAK;EACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,MAAM;CACR;CAEA,IAAI;CACJ,IAAI;EACF,QAAQ,qBAAqB,gBAAgB;CAC/C,SAAS,KAAK;EACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,MAAM;CACR;CACA,IAAI;EACF,MAAM,aAAa,UAAU;EAC7B,MAAM,WAAW,UAAU;EAC3B,MAAM,sBAAsB,UAAU;CACxC,SAAS,KAAK;EACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,uBAAuB;EACvB,MAAM,QAAQ;EACd,MAAM;CACR;CAKA,WAAW,GAAG,6BAAqE;EACjF,IAAI,CAAC,IAAI,oBAAoB;EAC7B,MAAM,WAAW,IAAI,mBAAmB,MAAM;EAC9C,IAAI,SAAS,WAAW,GAAG;EAU3B,OAAO,EAAE,gBAPe;GACtB;GACA,GAAG;GACH;GACA;EACF,EAAE,KAAK,IAEgC,EAAE;CAC3C,CAAC;CAKD,WAAW,GAAG,cAAc,OAAgB;EAC1C,MAAM,QAAQ;EACd,IAAI,CAAC,OAAO,mBAAmB,CAAC,MAAM,QAAQ,MAAM,eAAe,GAAG;EACtE,IAAI,YAAY,0BAA0B,MAAM,eAAgC;EAChF,YAAY,mCAAmC,SAAS;EACxD,IAAI,cAAc,MAAM,iBAAiB;GACvC,MAAM,gBAAgB,SAAS;GAC/B,KAAK,MAAM,KAAK,WAAW,MAAM,gBAAgB,KAAK,CAAC;EACzD;CACF,CAAC;CAkBD,MAAM,sBAAsB,IAAI,IAAI,WAAW,mBAAmB;CAClE,IAAI,IAAI,IAAI,WAAW,WAAW,wBAAwB,SAAS,IAAI,IAAI,cAAc,UAAU;EACjG,IAAI,2BAA0C;EAG9C,MAAM,gCAAwC;GAC5C,MAAM,OAAO,oBAAoB;GAGjC,OAAO;IACL;IACA;IACA,yBAJA,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,sEAIH;IACjC;IACA;IACA;IACA;IACA;GACF,EAAE,KAAK,IAAI;EACb;EAMA,WAAW,GAAG,wBAAwB,OAAgB,YAA6D;GACjH,IAAI,CAAC,0BACH,2BAA2B,wBAAwB;GAErD,IAAI,wBAAwB,WAAW;IAErC,MAAM,aACJ,+BAA+B,OAFpB,sBAAsB,KAAK,OAEG,CAAC,KAAK,iBAAiB,kBAAkB,SAAS;IAC7F,IAAI,MAAM,aAAa,4BAA4B,IAAI,UAAU,GAAG;IACpE,MAAM,aAAa,4BAA4B,IAAI,UAAU;IAC7D,MAAM,aAAa,aAAa,UAAU;IAC1C,MAAM,aAAa,iBAAiB;GACtC;GACA,OAAO,EAAE,gBAAgB,yBAAyB;EACpD,CAAC;CACH;CAUA,IAAI;EACF,WAAW,GAAG,qBAAqB,OAAO,OAAgB,YAAqB;GAC7E,MAAM,KAAK;GAOX,MAAM,YAAY,mCAAmC,OAAO,OAAO;GACnE,IAAI,WAAW;IACb,MAAM,QAAQ,6BAA6B;KACzC,OAAO;KACP,OAAO,UAAU;KACjB,UAAU,UAAU;KACpB,QAAQ,UAAU;IACpB,CAAC;IACD,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK;GACpC,OAAO;IACL,IAAI,OAAO,QACT,4FACF;IACA,iCAAiC,KAAK,qBAAqB;KAAE;KAAO;IAAQ,CAAC;GAC/E;GAEA,MAAM,yBACJ;IAAE,KAAK,IAAI;IAAK,SAAS,IAAI;IAAS,UAAU,IAAI;IAAU,YAAY,IAAI;GAAW,GACzF,IAAI,QACJ,mBACF;GAGA,MAAM,WAAW,GAAG,gBAAgB;GACpC,MAAM,aAAa,GAAG,cAAc;GACpC,IAAI,OAAO,OACT,+CAA+C,SAAS,UAAU,WAAW,cAAc,GAAG,mBAAmB,KACnH;GACA,IAAI,CAAC,iCAAiC;IACpC,kCAAkC;IAClC,8BAA8B;KAC5B,QAAQ,IAAI;KACZ,WAAW;KACX,WAAW;KACX,OAAO;KACP,SAAS;KACT,MAAM;MACJ,cAAc;MACd;MACA,iBAAiB,GAAG,mBAAmB;KACzC;IACF,CAAC;GACH;GAEA,IAAI,kBAAkB;GAEtB,IAAI;IACF,MAAM,KAAK,MAAM,OAAO;IACxB,IAAI,OAAO,IAAI,gBAAgB,YAAY;KACzC,MAAM,eAAe,IAAI,YAAY,WAAW;KAChD,IAAI,GAAG,WAAW,YAAY,GAAG;MAC/B,MAAM,UAAU,GAAG,aAAa,cAAc,OAAO;MACrD,mBAAmB,iDAAiD,QAAQ;KAC9E;IACF;GACF,SAAS,KAAK;IACZ,IAAI,OAAO,QAAQ,+DAA+D,KAAK;GACzF;GAEA,IAAI;IACF,MAAM,cAAc;KAClB,WAAW,IAAI,SAAS;KACxB,SAAS,IAAI,SAAS;KACtB,QAAQ,IAAI,SAAS;IACvB;IACA,MAAM,WAAW,IAAI,QAAQ,YAAY,KAAM,WAAW;IAC1D,MAAM,wBAAwB,IAAI,IAAI,YAAY,gCAAgC;IAElF,MAAM,cAAc,SAAS,QAC1B,MAAM,EAAE,MAAM,eAAe,gBAAgB,EAAE,MAAM,eAAe,MAAM,qBAC7E;IAEA,IAAI,YAAY,SAAS,GAAG;KAC1B,mBAAmB;KACnB,mBAAmB,GAAG,YAAY,KAAK,MAAM,KAAK,EAAE,MAAM,WAAW,EAAE,MAAM,MAAM,EAAE,KAAK,IAAI,EAAE;IAClG;GACF,SAAS,KAAK;IACZ,IAAI,OAAO,QAAQ,mEAAmE,KAAK;GAC7F;GAEA,IAAI,gBAAgB,KAAK,EAAE,SAAS,GAClC,OAAO,EACL,gBAAgB,iKAAiK,gBAAgB,wDACnM;EAGJ,CAAC;CACH,SAAS,KAAK;EAEZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,IAAI,OAAO,QAAQ,wDAAwD,IAAI,EAAE;CACnF;CAKA,IAAI;EACF,WAAW,GACT,oBACA,OAAO,OAAgB,YAAsE;GAC3F,MAAM,KAAK;GAOX,MAAM,YAAY,mCAAmC,OAAO,OAAO;GACnE,IAAI,WAAW;IACb,MAAM,QAAQ,6BAA6B;KACzC,OAAO;KACP,OAAO,UAAU;KACjB,UAAU,UAAU;KACpB,QAAQ,UAAU;IACpB,CAAC;IACD,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK;GACpC,OAAO;IACL,IAAI,OAAO,QACT,2FACF;IACA,iCAAiC,KAAK,oBAAoB;KAAE;KAAO;IAAQ,CAAC;GAC9E;GAEA,MAAM,WAAW,GAAG,gBAAgB;GACpC,MAAM,YAAY,GAAG,kBAAkB;GACvC,MAAM,aAAa,GAAG,cAAc;GAEpC,IAAI,OAAO,OACT,8CAA8C,SAAS,UAAU,WAAW,aAAa,WAC3F;GAGA,IAAI,IAAI,IAAI,cAAc,UAAU;GAGpC,IAAI,YAAY;GAChB,IAAI;IACF,YAAY,IAAI,QAAQ,SAAS;IACjC,IAAI,OAAO,QAAQ,uDAAuD,UAAU,gBAAgB;GACtG,SAAS,OAAO;IACd,IAAI,OAAO,OACT,iEAAiE,MAAM,2CACzE;IAEA;GACF;GAWA,IAAI;IACF,MAAM,SAAmB,CAAC;IAE1B,IAAI,IAAI,IAAI,WAAW,SAAS;KAC9B,MAAM,aAAa,iBAAiB,wBAAwB;KAC5D,IAAI,OAAO,eAAe,YAAY,WAAW,KAAK,EAAE,UAAU,GAAG;MACnE,MAAM,cAAc,MAAM,iCAAiC,kBAAkB,KAAK,UAAU;MAC5F,IAAI,aAAa;OACf,OAAO,KAAK,WAAW;OACvB,IAAI,OAAO,QAAQ,mFAAmF;MACxG;KACF;IACF;IAEA,MAAM,eAAe,IAAI,QAAQ,KAAK,CAAC;IACvC,MAAM,eAAyB,CAAC;IAEhC,IAAI,aAAa,SAAS,GAAG;KAC3B,aAAa,KAAK,wDAAwD;KAC1E,aAAa,KAAK,0CAA0C;KAC5D,KAAK,MAAM,KAAK,cAAc;MAC5B,MAAM,eAAe,EAAE,SAAS,IAAI,EAAE,OAAO,MAAM;MACnD,MAAM,UAAU,EAAE,KAAK,SAAS,MAAM,GAAG,EAAE,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE;MACrE,aAAa,KAAK,KAAK,eAAe,SAAS;KACjD;IACF;IAGA,IAAI,IAAI,YACN,IAAI;KACF,MAAM,aAAa,IAAI,WAAW,KAAK;MACrC,QAAQ;OAAC;OAAQ;OAAa;MAAe;MAC7C,OAAO;KACT,CAAC;KACD,IAAI,WAAW,SAAS,GAAG;MACzB,aAAa,KAAK,EAAE;MACpB,aAAa,KAAK,cAAc;MAChC,KAAK,MAAM,SAAS,YAClB,aAAa,KAAK,MAAM,MAAM,SAAS,IAAI,MAAM,MAAM,IAAI,MAAM,OAAO,EAAE;KAE9E;IACF,QAAQ,CAER;IAGF,IAAI,aAAa,SAAS,GAAG;KAC3B,aAAa,KAAK,yDAAyD;KAC3E,OAAO,KAAK,aAAa,KAAK,IAAI,CAAC;IACrC;IAEA,IAAI,OAAO,SAAS,GAAG;KACrB,IAAI,OAAO,QACT,wEAAwE,aAAa,OAAO,gBAC9F;KACA,OAAO,EAAE,gBAAgB,OAAO,KAAK,MAAM,EAAE;IAC/C;GACF,QAAQ,CAER;EACF,CACF;CACF,SAAS,KAAK;EAEZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW;EACb,CAAC;EACD,IAAI,OAAO,QAAQ,uDAAuD,IAAI,EAAE;CAClF;CAQA,IAAI,WAAW;CACf,OAAO,EACL,eAAe;EACb,IAAI,UAAU;EACd,WAAW;EACX,uBAAuB;EACvB,MAAM,QAAQ;CAChB,EACF;AACF"}
|