hippo-memory 1.71.0 → 1.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +6 -21
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/copilot.d.ts +1 -3
- package/dist/agent-memories/copilot.js +1 -17
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/sync.js +8 -6
- package/dist/api/assemble.js +1 -1
- package/dist/api/audit.d.ts +29 -1
- package/dist/api/audit.js +44 -5
- package/dist/api/auth.d.ts +7 -4
- package/dist/api/auth.js +12 -8
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +7 -3
- package/dist/api/availability.js +2 -3
- package/dist/api/cards.d.ts +42 -0
- package/dist/api/cards.js +52 -0
- package/dist/api/conflicts.d.ts +28 -0
- package/dist/api/conflicts.js +61 -0
- package/dist/api/context-render.js +4 -3
- package/dist/api/context-select.js +9 -11
- package/dist/api/context.js +17 -8
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/api/dormant.js +4 -2
- package/dist/api/drill-down.js +1 -1
- package/dist/api/embeddings.d.ts +17 -0
- package/dist/api/embeddings.js +28 -0
- package/dist/api/error-reply.d.ts +8 -0
- package/dist/api/error-reply.js +21 -0
- package/dist/api/forget.d.ts +6 -2
- package/dist/api/forget.js +18 -7
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +4 -2
- package/dist/api/instruction-detect.js +5 -1
- package/dist/api/learn.d.ts +4 -0
- package/dist/api/learn.js +53 -27
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +19 -1
- package/dist/api/memories.js +39 -0
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/outcome.js +1 -1
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +3 -1
- package/dist/api/predictions.js +6 -0
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.js +1 -1
- package/dist/api/prompt-hook.d.ts +15 -2
- package/dist/api/prompt-hook.js +44 -4
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +3 -3
- package/dist/api/recall-pipeline.js +6 -7
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +19 -44
- package/dist/api/remember-local.js +1 -1
- package/dist/api/remember.d.ts +2 -1
- package/dist/api/remember.js +3 -2
- package/dist/api/session-end.d.ts +22 -0
- package/dist/api/session-end.js +101 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +13 -9
- package/dist/api/status.d.ts +24 -0
- package/dist/api/status.js +40 -0
- package/dist/api/store-init.d.ts +4 -0
- package/dist/api/store-init.js +9 -0
- package/dist/api/tokens.js +1 -1
- package/dist/api/types.d.ts +2 -0
- package/dist/api/types.js +6 -1
- package/dist/capture/caller-session.d.ts +0 -3
- package/dist/capture/caller-session.js +1 -12
- package/dist/capture/capture-error.d.ts +2 -2
- package/dist/capture/capture-error.js +23 -18
- package/dist/capture/codex-patch.js +3 -1
- package/dist/capture/command.js +36 -95
- package/dist/capture/compact.js +10 -5
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +29 -426
- package/dist/capture/compaction-spool.d.ts +4 -2
- package/dist/capture/compaction-spool.js +20 -6
- package/dist/capture/copilot-transcript.d.ts +2 -1
- package/dist/capture/copilot-transcript.js +2 -1
- package/dist/capture/extract.d.ts +5 -2
- package/dist/capture/extract.js +4 -3
- package/dist/capture/failure-caller.d.ts +1 -1
- package/dist/capture/failure-caller.js +21 -16
- package/dist/capture/failure-reading.d.ts +2 -1
- package/dist/capture/failure-reading.js +7 -9
- package/dist/capture/pre-compact-caller.js +5 -4
- package/dist/capture/session-digest.js +4 -3
- package/dist/capture/session-end-caller.js +2 -1
- package/dist/capture/session-worker.js +3 -4
- package/dist/capture/transcript.d.ts +2 -1
- package/dist/capture/transcript.js +6 -3
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/audit-prune.d.ts +0 -25
- package/dist/cli/audit-prune.js +1 -27
- package/dist/cli/audit.js +13 -13
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +12 -13
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +37 -292
- package/dist/cli/card.js +41 -33
- package/dist/cli/client.d.ts +5 -0
- package/dist/cli/client.js +24 -8
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +12 -12
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +23 -27
- package/dist/cli/dag.d.ts +1 -1
- package/dist/cli/dag.js +23 -8
- package/dist/cli/decisions.d.ts +0 -2
- package/dist/cli/decisions.js +4 -281
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +12 -13
- package/dist/cli/explain.d.ts +1 -1
- package/dist/cli/explain.js +21 -25
- package/dist/cli/flag-values.js +16 -6
- package/dist/cli/flags.d.ts +0 -289
- package/dist/cli/flags.js +3 -138
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +3 -5
- package/dist/cli/hook-runtime.js +7 -34
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.js +28 -19
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +11 -3
- package/dist/cli/last-sleep.js +1 -1
- package/dist/cli/lenient-id.d.ts +2 -0
- package/dist/cli/lenient-id.js +13 -0
- package/dist/cli/maintenance.d.ts +3 -3
- package/dist/cli/maintenance.js +29 -30
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +126 -290
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +175 -0
- package/dist/cli/print.js +2 -1
- package/dist/cli/projects.js +30 -22
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +6 -5
- package/dist/cli/recall.js +13 -7
- package/dist/cli/refine-llm.js +17 -17
- package/dist/cli/remember.js +12 -12
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +3 -3
- package/dist/cli/session-hooks.d.ts +1 -1
- package/dist/cli/session-hooks.js +45 -115
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +17 -10
- package/dist/cli/shared.d.ts +2 -6
- package/dist/cli/shared.js +9 -29
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.js +6 -37
- package/dist/cli/status.d.ts +3 -3
- package/dist/cli/status.js +32 -35
- package/dist/cli/transfer.d.ts +1 -1
- package/dist/cli/transfer.js +33 -31
- package/dist/cli/usage.d.ts +0 -79
- package/dist/cli/usage.js +1 -695
- package/dist/cli/verb-row.d.ts +32 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +232 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +244 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +254 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +312 -0
- package/dist/cli/verbs.d.ts +81 -0
- package/dist/cli/verbs.js +7 -0
- package/dist/cli/versioned-verbs.d.ts +51 -0
- package/dist/cli/versioned-verbs.js +79 -0
- package/dist/cli.d.ts +1 -272
- package/dist/cli.js +23 -313
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +37 -3
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +3 -28
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +33 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +28 -0
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +2 -27
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +1 -1
- package/dist/consolidate/dag.js +15 -9
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +5 -3
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +2 -1
- package/dist/consolidate/merge.js +2 -2
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +26 -6
- package/dist/consolidate/replay.js +11 -4
- package/dist/consolidate/sleep.js +8 -5
- package/dist/consolidate/traces.js +3 -3
- package/dist/core/ablation.d.ts +10 -0
- package/dist/core/ablation.js +12 -0
- package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
- package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
- package/dist/core/ambient.d.ts +4 -0
- package/dist/core/ambient.js +39 -18
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/card.js +3 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +7 -2
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/{store → core}/markdown.d.ts +1 -1
- package/dist/{store → core}/markdown.js +2 -2
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +10 -4
- package/dist/core/memory.js +25 -18
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.js +6 -16
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +3 -0
- package/dist/core/project-identity.js +10 -1
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +0 -1
- package/dist/db/connect.js +5 -6
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +0 -2
- package/dist/db/open.js +6 -10
- package/dist/db/physics-state.js +3 -3
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +17 -4
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.js +11 -8
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
- package/dist/{store/embeddings → embeddings}/provider.js +18 -15
- package/dist/embeddings/transformers.d.ts +26 -0
- package/dist/embeddings/transformers.js +89 -0
- package/dist/entry/session-text.d.ts +1 -1
- package/dist/entry/session-text.js +1 -1
- package/dist/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +11 -4
- package/dist/graph/extract.js +3 -3
- package/dist/graph/recall.js +1 -1
- package/dist/graph/view.js +13 -5
- package/dist/graph/write.d.ts +1 -1
- package/dist/graph/write.js +9 -9
- package/dist/hooks/codex-session.js +3 -2
- package/dist/hooks/codex-wrapper.js +2 -1
- package/dist/hooks/json-hooks.js +4 -2
- package/dist/hooks/opencode.js +8 -5
- package/dist/hooks/shared.d.ts +0 -6
- package/dist/hooks/shared.js +4 -15
- package/dist/importers/core.js +1 -1
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.js +7 -5
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/learn/autolearn.d.ts +10 -2
- package/dist/learn/autolearn.js +32 -12
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +6 -4
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.js +10 -6
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +27 -48
- package/dist/mcp/format.js +3 -2
- package/dist/mcp/framing.d.ts +1 -0
- package/dist/mcp/framing.js +1 -1
- package/dist/mcp/memory-tools.js +3 -1
- package/dist/mcp/protocol.d.ts +11 -7
- package/dist/mcp/protocol.js +25 -12
- package/dist/mcp/recall-tools.js +12 -9
- package/dist/mcp/request.js +2 -1
- package/dist/mcp/stdio.js +24 -8
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +44 -21
- package/dist/objects/customer-notes.d.ts +2 -2
- package/dist/objects/decisions.d.ts +2 -2
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +2 -2
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +2 -2
- package/dist/objects/policies.js +2 -1
- package/dist/objects/processes.d.ts +2 -2
- package/dist/objects/project-briefs.d.ts +2 -2
- package/dist/objects/project-briefs.js +2 -3
- package/dist/objects/skills.d.ts +2 -2
- package/dist/postinstall.js +1 -1
- package/dist/rerankers/clef.js +3 -6
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +63 -97
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +2 -4
- package/dist/rerankers/outage-warning.d.ts +3 -1
- package/dist/rerankers/outage-warning.js +5 -3
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.js +1 -1
- package/dist/search/embed-memories.d.ts +9 -0
- package/dist/search/embed-memories.js +377 -0
- package/dist/search/goal-boost.d.ts +1 -1
- package/dist/search/goal-boost.js +6 -3
- package/dist/search/hybrid.d.ts +9 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +22 -15
- package/dist/search/rerank.js +1 -1
- package/dist/search/vector.d.ts +8 -6
- package/dist/search/vector.js +10 -13
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +17 -7
- package/dist/server/boot.js +7 -66
- package/dist/server/client-ip.d.ts +0 -2
- package/dist/server/client-ip.js +3 -2
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +1 -0
- package/dist/server/defaults.js +1 -0
- package/dist/server/mcp-http.js +16 -11
- package/dist/server/request.js +7 -2
- package/dist/server/route-checks.d.ts +7 -0
- package/dist/server/route-checks.js +42 -0
- package/dist/server/route-table.d.ts +9 -8
- package/dist/server/route-table.js +127 -132
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +13 -21
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +1 -2
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +2 -4
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +2 -5
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +15 -38
- package/dist/server/routes/object-routes.d.ts +6 -6
- package/dist/server/routes/object-routes.js +4 -7
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +2 -4
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +9 -13
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +1 -2
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +2 -4
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +6 -10
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +2 -4
- package/dist/server/server-detect.d.ts +7 -1
- package/dist/server/server-detect.js +36 -11
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +17 -11
- package/dist/server/types.d.ts +22 -10
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +5 -4
- package/dist/server.js +5 -4
- package/dist/sharing/global-store.js +2 -2
- package/dist/sharing/global-sync.js +38 -45
- package/dist/sharing/project-merge.d.ts +7 -14
- package/dist/sharing/project-merge.js +57 -121
- package/dist/sharing/search-both.js +1 -1
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +37 -34
- package/dist/store/ambient.js +5 -6
- package/dist/store/audit-event.d.ts +1 -1
- package/dist/store/audit.d.ts +0 -16
- package/dist/store/audit.js +4 -55
- package/dist/store/auth.d.ts +4 -2
- package/dist/store/auth.js +7 -3
- package/dist/store/candidates.d.ts +3 -2
- package/dist/store/candidates.js +42 -23
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +1 -1
- package/dist/store/compaction-caller.d.ts +18 -0
- package/dist/store/compaction-caller.js +29 -0
- package/dist/store/compactions-record.d.ts +115 -0
- package/dist/store/compactions-record.js +417 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.js +7 -4
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +32 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +30 -53
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +18 -47
- package/dist/store/dashboard-reads.js +7 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +36 -3
- package/dist/store/delivery-recorder.d.ts +10 -3
- package/dist/store/delivery-recorder.js +12 -5
- package/dist/store/descendant-page.js +6 -3
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +3 -1
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +13 -4
- package/dist/store/entry-reads.js +47 -11
- package/dist/store/entry-writes.d.ts +5 -5
- package/dist/store/entry-writes.js +32 -12
- package/dist/store/failure-log-at.d.ts +8 -0
- package/dist/store/failure-log-at.js +16 -0
- package/dist/store/failure-log.d.ts +2 -2
- package/dist/store/failure-log.js +5 -3
- package/dist/{trust → store}/gated-write.d.ts +3 -1
- package/dist/{trust → store}/gated-write.js +7 -5
- package/dist/store/goals.js +20 -18
- package/dist/store/graph-reads.js +4 -2
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/handoffs.d.ts +1 -1
- package/dist/store/handoffs.js +6 -6
- package/dist/store/index-and-stats.js +2 -2
- package/dist/store/key-writes.js +1 -1
- package/dist/store/ledger-turn.d.ts +9 -0
- package/dist/store/ledger-turn.js +38 -0
- package/dist/store/mirrors.js +10 -6
- package/dist/store/open.d.ts +0 -4
- package/dist/store/open.js +40 -53
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +9 -3
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +1 -2
- package/dist/store/predictions.js +3 -6
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/store/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +18 -2
- package/dist/store/rejected-values.js +2 -1
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +0 -17
- package/dist/store/rejection.js +1 -21
- package/dist/store/rule-sql.d.ts +9 -0
- package/dist/store/rule-sql.js +21 -2
- package/dist/store/search-rows.js +9 -4
- package/dist/store/sessions.js +4 -2
- package/dist/store/set-aside.d.ts +14 -0
- package/dist/store/set-aside.js +23 -0
- package/dist/store/sqlite/busy.d.ts +3 -0
- package/dist/store/sqlite/busy.js +8 -0
- package/dist/store/sqlite/connector-events-group.js +4 -7
- package/dist/store/sqlite/connector-writes-group.js +3 -3
- package/dist/store/sqlite/entry-writes-group.js +2 -2
- package/dist/store/sqlite/error-codec.js +4 -3
- package/dist/store/sqlite/executor.js +10 -4
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +9 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +1 -1
- package/dist/store/sqlite/store.js +14 -12
- package/dist/store/summaries.d.ts +3 -3
- package/dist/store/summaries.js +5 -4
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +3 -2
- package/dist/support-bundle.js +2 -3
- package/dist/trust/reject-flow.js +2 -2
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +3 -0
- package/dist/util/anthropic-messages.js +22 -5
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +2 -1
- package/dist/util/env.js +2 -1
- package/dist/util/format.d.ts +3 -0
- package/dist/util/format.js +6 -0
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +6 -0
- package/dist/util/http-retry.js +43 -5
- package/dist/util/http-util.d.ts +0 -8
- package/dist/util/http-util.js +10 -21
- package/dist/util/limits.d.ts +7 -0
- package/dist/util/limits.js +14 -0
- package/dist/util/log.d.ts +4 -0
- package/dist/util/log.js +9 -0
- package/dist/util/request-scope.d.ts +3 -1
- package/dist/util/request-scope.js +11 -6
- package/dist/util/secret-detect.js +6 -1
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stream-tee.d.ts +3 -0
- package/dist/util/stream-tee.js +35 -0
- package/dist/util/time.d.ts +4 -0
- package/dist/util/time.js +4 -0
- package/dist/util/version.d.ts +1 -1
- package/dist/util/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -175
- /package/dist/{cli → api}/correction-latency.d.ts +0 -0
- /package/dist/{cli → api}/correction-latency.js +0 -0
- /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
- /package/dist/{cli → api}/provenance-coverage.js +0 -0
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
- /package/dist/{store → util}/yaml.d.ts +0 -0
- /package/dist/{store → util}/yaml.js +0 -0
|
@@ -52,7 +52,8 @@ import { v51 } from './v51.js';
|
|
|
52
52
|
import { v52 } from './v52.js';
|
|
53
53
|
import { v53 } from './v53.js';
|
|
54
54
|
import { v54 } from './v54.js';
|
|
55
|
-
|
|
55
|
+
import { v55 } from './v55.js';
|
|
56
|
+
export const CURRENT_SCHEMA_VERSION = 55;
|
|
56
57
|
/** Every schema migration in version order; runMigrations applies each one above the stored version. */
|
|
57
58
|
export const MIGRATIONS = [
|
|
58
59
|
v01,
|
|
@@ -109,5 +110,6 @@ export const MIGRATIONS = [
|
|
|
109
110
|
v52,
|
|
110
111
|
v53,
|
|
111
112
|
v54,
|
|
113
|
+
v55,
|
|
112
114
|
];
|
|
113
115
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tableHasColumn, tableExists } from '../tables.js';
|
|
2
|
+
export const v55 = {
|
|
3
|
+
version: 55,
|
|
4
|
+
up: (db) => {
|
|
5
|
+
// No backfill and no floor raise: an older binary names its INSERT columns, so it still writes.
|
|
6
|
+
if (!tableExists(db, 'delivery_events'))
|
|
7
|
+
return;
|
|
8
|
+
if (!tableHasColumn(db, 'delivery_events', 'tool_use_id'))
|
|
9
|
+
db.exec('ALTER TABLE delivery_events ADD COLUMN tool_use_id TEXT');
|
|
10
|
+
if (!tableHasColumn(db, 'delivery_events', 'failure_id'))
|
|
11
|
+
db.exec('ALTER TABLE delivery_events ADD COLUMN failure_id INTEGER');
|
|
12
|
+
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_delivery_events_tool_call
|
|
13
|
+
ON delivery_events(tenant_id, session_id, tool_use_id)
|
|
14
|
+
WHERE tool_use_id IS NOT NULL AND turn_seq IS NOT NULL`);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=v55.js.map
|
package/dist/db/open.d.ts
CHANGED
|
@@ -24,8 +24,6 @@ export declare function withSqliteAllowed<T>(fn: () => T): T;
|
|
|
24
24
|
export declare function withSqliteOffLoop<T>(fn: () => T): T;
|
|
25
25
|
/** Leaves withSqliteOffLoop's block and nothing else: another store's block and the folder marker still refuse, which withSqliteAllowed would waive. */
|
|
26
26
|
export declare function outsideSqliteOffLoop<T>(fn: () => T): T;
|
|
27
|
-
/** First line of a best-effort catch around a hippo.db open: an unported path must fail closed, not fall back silently. */
|
|
28
|
-
export declare function rethrowIfSqliteBlocked<E>(err: E): void;
|
|
29
27
|
/** store init --db, store copy --db and serve --db write this file in the hippo root; its text is the store kind. */
|
|
30
28
|
export declare const OTHER_STORE_MARKER = "other-store";
|
|
31
29
|
/** Throws where hippo.db must not open; checked on every open, not cached, since the marker can appear while a process runs. */
|
package/dist/db/open.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import { errorMessage, log } from '../util/log.js';
|
|
4
|
+
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
5
5
|
import { DatabaseSync } from './sqlite.js';
|
|
6
6
|
import { tableExists } from './tables.js';
|
|
7
7
|
import { assertBinaryCompatible } from './migrate.js';
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_BUSY_WAIT_MS } from './busy.js';
|
|
9
|
+
import { connectWithFacts, getHippoDbPath } from './connect.js';
|
|
9
10
|
import { currentRequestStores, isScopedHandle, runWithRequestStores } from './request-stores.js';
|
|
10
11
|
import { OtherStoreFolderError, SqliteBlockedError } from '../util/sqlite-blocked.js';
|
|
11
12
|
export { getHippoDbPath };
|
|
@@ -49,11 +50,6 @@ export function withSqliteOffLoop(fn) {
|
|
|
49
50
|
export function outsideSqliteOffLoop(fn) {
|
|
50
51
|
return sqliteBlockedBy.getStore() === OFF_LOOP ? sqliteBlockedBy.exit(fn) : fn();
|
|
51
52
|
}
|
|
52
|
-
/** First line of a best-effort catch around a hippo.db open: an unported path must fail closed, not fall back silently. */
|
|
53
|
-
export function rethrowIfSqliteBlocked(err) {
|
|
54
|
-
if (err instanceof SqliteBlockedError)
|
|
55
|
-
throw err;
|
|
56
|
-
}
|
|
57
53
|
/** store init --db, store copy --db and serve --db write this file in the hippo root; its text is the store kind. */
|
|
58
54
|
export const OTHER_STORE_MARKER = 'other-store';
|
|
59
55
|
const markerWaived = new AsyncLocalStorage();
|
|
@@ -95,7 +91,7 @@ export function openHippoDbReadOnly(hippoRoot) {
|
|
|
95
91
|
assertSqliteAllowed(hippoRoot);
|
|
96
92
|
const db = new DatabaseSync(getHippoDbPath(hippoRoot), { readOnly: true });
|
|
97
93
|
try {
|
|
98
|
-
db.exec(
|
|
94
|
+
db.exec(`PRAGMA busy_timeout = ${DEFAULT_BUSY_WAIT_MS}`);
|
|
99
95
|
if (tableExists(db, 'meta'))
|
|
100
96
|
assertBinaryCompatible(db);
|
|
101
97
|
return db;
|
|
@@ -104,8 +100,8 @@ export function openHippoDbReadOnly(hippoRoot) {
|
|
|
104
100
|
try {
|
|
105
101
|
db.close();
|
|
106
102
|
}
|
|
107
|
-
catch {
|
|
108
|
-
|
|
103
|
+
catch (closeErr) {
|
|
104
|
+
log.error(`openHippoDbReadOnly: closing the handle after a failed open failed: ${errorMessage(closeErr)}`, errorFields(closeErr));
|
|
109
105
|
}
|
|
110
106
|
throw error;
|
|
111
107
|
}
|
package/dist/db/physics-state.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Physics state persistence: particle state (position, velocity, mass, charge, temperature) in SQLite, with BLOB columns for 384-dim vectors. */
|
|
2
|
-
import { evalNow } from '../core/ablation.js';
|
|
2
|
+
import { evalNow, strengthAblation } from '../core/ablation.js';
|
|
3
3
|
import { withWriteScope } from './busy.js';
|
|
4
4
|
import { computeMass, computeCharge, computeTemperature, vecZero } from '../core/physics.js';
|
|
5
5
|
import { calculateStrength } from '../core/memory.js';
|
|
@@ -99,7 +99,7 @@ export function savePhysicsState(db, particles) {
|
|
|
99
99
|
}
|
|
100
100
|
/** Initialize physics state for a memory from its embedding vector; returns the new particle without persisting (the caller must save). */
|
|
101
101
|
export function initializeParticle(entry, embedding, now = evalNow()) {
|
|
102
|
-
const strength = calculateStrength(entry, now);
|
|
102
|
+
const strength = calculateStrength(entry, now, { ablation: strengthAblation() });
|
|
103
103
|
const ageDays = (now.getTime() - new Date(entry.created).getTime()) / DAY_MS;
|
|
104
104
|
return {
|
|
105
105
|
memoryId: entry.id,
|
|
@@ -141,7 +141,7 @@ export function refreshParticleProperties(particles, entries, now = evalNow()) {
|
|
|
141
141
|
const entry = entries.get(p.memoryId);
|
|
142
142
|
if (!entry)
|
|
143
143
|
continue;
|
|
144
|
-
const strength = calculateStrength(entry, now);
|
|
144
|
+
const strength = calculateStrength(entry, now, { ablation: strengthAblation() });
|
|
145
145
|
const ageDays = (now.getTime() - new Date(entry.created).getTime()) / DAY_MS;
|
|
146
146
|
p.mass = computeMass(strength, entry.retrieval_count);
|
|
147
147
|
p.charge = computeCharge(entry.emotional_valence);
|
package/dist/db/tables.d.ts
CHANGED
|
@@ -7,5 +7,7 @@ export declare function tableExists(db: DatabaseSyncLike, tableName: string): bo
|
|
|
7
7
|
export declare function listTableNames(db: DatabaseSyncLike): string[];
|
|
8
8
|
/** Row count of one table; null when the table is missing or unreadable, which callers show as unknown. */
|
|
9
9
|
export declare function countTableRows(db: DatabaseSyncLike, table: string): number | null;
|
|
10
|
+
/** Sleep runs a store keeps; stats.json lists exactly these, so a recall's stats rewrite reads a fixed number of rows. */
|
|
11
|
+
export declare const CONSOLIDATION_RUNS_KEPT = 50;
|
|
10
12
|
export declare function pruneConsolidationRuns(db: DatabaseSyncLike, keep?: number): void;
|
|
11
13
|
//# sourceMappingURL=tables.d.ts.map
|
package/dist/db/tables.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorCode, log } from '../util/log.js';
|
|
1
2
|
/** Column names of one table; empty when the table is missing. */
|
|
2
3
|
export function tableColumns(db, tableName) {
|
|
3
4
|
if (!/^[a-z_]+$/i.test(tableName))
|
|
@@ -30,12 +31,15 @@ export function countTableRows(db, table) {
|
|
|
30
31
|
const row = db.prepare(`SELECT COUNT(*) AS n FROM "${table.replace(/"/g, '""')}"`).get();
|
|
31
32
|
return Number(row?.n ?? 0);
|
|
32
33
|
}
|
|
33
|
-
catch {
|
|
34
|
+
catch (err) {
|
|
34
35
|
// Callers treat an uncountable table as unknown; the bundle and doctor still finish.
|
|
36
|
+
log.warn(`could not count rows in table ${table}`, { table, code: errorCode(err) || 'unknown' });
|
|
35
37
|
return null;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
/** Sleep runs a store keeps; stats.json lists exactly these, so a recall's stats rewrite reads a fixed number of rows. */
|
|
41
|
+
export const CONSOLIDATION_RUNS_KEPT = 50;
|
|
42
|
+
export function pruneConsolidationRuns(db, keep = CONSOLIDATION_RUNS_KEPT) {
|
|
39
43
|
db.prepare(`
|
|
40
44
|
DELETE FROM consolidation_runs
|
|
41
45
|
WHERE id NOT IN (
|
package/dist/db/vector-store.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { withWriteScope } from './busy.js';
|
|
5
|
-
import { log } from '../util/log.js';
|
|
5
|
+
import { errorCode, errorFields, log } from '../util/log.js';
|
|
6
6
|
/** Legacy whole-file index; imported once into `memory_vectors`, then kept beside the store as a renamed backup. */
|
|
7
7
|
const LEGACY_EMBEDDINGS_FILE = 'embeddings.json';
|
|
8
8
|
export const EMBEDDING_MODEL_META_KEY = 'embedding_model';
|
|
@@ -188,17 +188,30 @@ function insertSorted(top, m, k) {
|
|
|
188
188
|
function stamp() {
|
|
189
189
|
return `${new Date().toISOString().replace(/[:.]/g, '-')}-${process.pid}`;
|
|
190
190
|
}
|
|
191
|
-
|
|
191
|
+
// The codes a rename gets when another process holds the file open (Windows); any other failure would fail a copy too.
|
|
192
|
+
const RENAME_BLOCKED_CODES = new Set(['EPERM', 'EBUSY', 'EACCES']);
|
|
193
|
+
/** Rename `fp` to `aside`; a rename blocked by an open handle falls back to a copy, so the bytes are kept either way. */
|
|
192
194
|
function moveAside(fp, aside) {
|
|
193
195
|
try {
|
|
194
196
|
fs.renameSync(fp, aside);
|
|
195
197
|
return true;
|
|
196
198
|
}
|
|
197
199
|
catch (err) {
|
|
198
|
-
|
|
200
|
+
const code = errorCode(err);
|
|
201
|
+
if (code === 'ENOENT')
|
|
199
202
|
return false;
|
|
203
|
+
if (!RENAME_BLOCKED_CODES.has(code))
|
|
204
|
+
throw err;
|
|
205
|
+
log.warn(`could not rename ${path.basename(fp)} aside (${code}); copying it instead`, { path: fp, ...errorFields(err) });
|
|
200
206
|
fs.copyFileSync(fp, aside, fs.constants.COPYFILE_EXCL);
|
|
201
|
-
|
|
207
|
+
try {
|
|
208
|
+
fs.rmSync(fp, { force: true });
|
|
209
|
+
}
|
|
210
|
+
catch (rmErr) {
|
|
211
|
+
// The original stays for the next open to retry, so a copy left beside it would pile up one per open.
|
|
212
|
+
fs.rmSync(aside, { force: true });
|
|
213
|
+
throw rmErr;
|
|
214
|
+
}
|
|
202
215
|
return true;
|
|
203
216
|
}
|
|
204
217
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { Worker } from 'node:worker_threads';
|
|
4
4
|
import { errorMessage, log } from '../util/log.js';
|
|
5
|
+
import { DEFAULT_BUSY_WAIT_MS } from './busy.js';
|
|
5
6
|
// WAL pages at which a connection checkpoints inside its own commit.
|
|
6
7
|
const INLINE_CHECKPOINT_PAGES = 100;
|
|
7
8
|
// The same limit while a worker checkpoints the store: SQLite still bounds the WAL when the worker falls behind.
|
|
@@ -17,7 +18,7 @@ const WORKER_SOURCE = `
|
|
|
17
18
|
const { parentPort, workerData } = require('node:worker_threads');
|
|
18
19
|
const { DatabaseSync } = require('node:sqlite');
|
|
19
20
|
const db = new DatabaseSync(workerData.dbPath);
|
|
20
|
-
db.exec('PRAGMA busy_timeout =
|
|
21
|
+
db.exec('PRAGMA busy_timeout = ${DEFAULT_BUSY_WAIT_MS}');
|
|
21
22
|
db.exec('PRAGMA synchronous = NORMAL');
|
|
22
23
|
const pass = db.prepare('PRAGMA wal_checkpoint(PASSIVE)');
|
|
23
24
|
parentPort.on('message', (message) => {
|
package/dist/doctor.js
CHANGED
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import * as os from 'node:os';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
|
-
import { findHippoStoreDir } from './core/project-identity.js';
|
|
6
|
+
import { findHippoStoreDir, isInitialized } from './core/project-identity.js';
|
|
7
7
|
import { getGlobalRoot } from './sharing/global-store.js';
|
|
8
|
-
import { isInitialized } from './store/open.js';
|
|
9
8
|
import { readStoreHealth } from './store/diagnostics.js';
|
|
10
9
|
import { loadConfig } from './core/config.js';
|
|
11
10
|
import { openHippoDbReadOnly, closeHippoDb, getCurrentSchemaVersion, IncompatibleBinaryError } from './db/index.js';
|
|
12
|
-
import { REPLAY_AFTER_MS, TRANSCRIPT_FILL_WINDOW_MS } from './
|
|
11
|
+
import { REPLAY_AFTER_MS, TRANSCRIPT_FILL_WINDOW_MS } from './core/compaction-timing.js';
|
|
13
12
|
import { SPOOL_DIR, spoolCounts } from './capture/compaction-spool.js';
|
|
14
|
-
import { isEmbeddingAvailable } from './
|
|
15
|
-
import { CODEX_TRUST_LINE,
|
|
13
|
+
import { isEmbeddingAvailable } from './embeddings/local.js';
|
|
14
|
+
import { CODEX_TRUST_LINE, isCodexPresent } from './hooks/shared.js';
|
|
15
|
+
import { claudeConfigDir, codexHomeDir } from './util/agent-homes.js';
|
|
16
16
|
import { planProjectRepair } from './sharing/project-merge.js';
|
|
17
|
+
import { projectTagReads } from './store/project-tags.js';
|
|
17
18
|
import { resolveTenantId } from './store/tenant.js';
|
|
18
19
|
import { errorMessage, log } from './util/log.js';
|
|
19
20
|
import { readJsonFile, isJsonObjectLiteral } from './util/json.js';
|
|
@@ -132,7 +133,8 @@ function compactionsCheck(compactions, store, now) {
|
|
|
132
133
|
].filter((s) => s !== '');
|
|
133
134
|
const unfinished = stuck === 0
|
|
134
135
|
? `${recorded} in the store`
|
|
135
|
-
: `${stuck} compaction${stuck === 1 ? '' : 's'} unfinished after 10 minutes
|
|
136
|
+
: `${stuck} compaction${stuck === 1 ? '' : 's'} unfinished after 10 minutes ` +
|
|
137
|
+
`(${summarised} with a summary whose memories are not saved yet, ${started} with no summary yet)`;
|
|
136
138
|
const note = spooled ? `; spool: ${spool.waiting} waiting, ${spool.stale} left by a replay that stopped, ${spool.bad} .bad` : '';
|
|
137
139
|
return { id: 'compactions', status: 'warn', detail: `${unfinished}${note}${unread}`, fix: fix.join('; ') };
|
|
138
140
|
}
|
|
@@ -141,7 +143,7 @@ function projectsCheck(globalRoot) {
|
|
|
141
143
|
let db = null;
|
|
142
144
|
try {
|
|
143
145
|
db = openHippoDbReadOnly(globalRoot);
|
|
144
|
-
const r = planProjectRepair(db,
|
|
146
|
+
const r = planProjectRepair(projectTagReads(db, resolveTenantId({})), globalRoot);
|
|
145
147
|
const found = [
|
|
146
148
|
r.copies.length > 0 ? `${r.copies.length} imported notes copied under the wrong project` : '',
|
|
147
149
|
r.folds.length > 0 ? `old project names that now resolve to another project: ${r.folds.map((f) => `${f.from} -> ${f.into}`).join(', ')}` : '',
|
|
@@ -253,7 +255,8 @@ function tokensCheck(tokens) {
|
|
|
253
255
|
return {
|
|
254
256
|
id: 'tokens',
|
|
255
257
|
status: 'info',
|
|
256
|
-
detail: `${tally.injected} memory blocks sent to agents in 7 days, about ${tally.tokensSent} tokens sent
|
|
258
|
+
detail: `${tally.injected} memory blocks sent to agents in 7 days, about ${tally.tokensSent} tokens sent ` +
|
|
259
|
+
`and ${tally.tokensReread} re-read by later model calls (hippo tokens for detail)`,
|
|
257
260
|
};
|
|
258
261
|
}
|
|
259
262
|
/** Checks that read the store's database; a store that cannot be opened becomes one failed schema check. */
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** The one call this file makes on a Transformers.js feature-extraction pipeline, and the part of its tensor it reads. */
|
|
2
|
+
interface EmbeddingPipeline {
|
|
3
|
+
(input: string, options: {
|
|
4
|
+
pooling: 'cls' | 'mean';
|
|
5
|
+
normalize: boolean;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
data: ArrayLike<number>;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
type PipelineFactory = (task: 'feature-extraction', model: string, options: {
|
|
11
|
+
quantized: boolean;
|
|
12
|
+
}) => Promise<EmbeddingPipeline>;
|
|
13
|
+
/** The settings written on the package's `env` object. */
|
|
14
|
+
interface TransformersEnv {
|
|
15
|
+
cacheDir?: string;
|
|
16
|
+
localModelPath?: string;
|
|
17
|
+
allowRemoteModels?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** The parts of the optional package's module this file reads; either export spelling may carry `pipeline`. */
|
|
20
|
+
interface TransformersModule {
|
|
21
|
+
env?: TransformersEnv;
|
|
22
|
+
pipeline?: PipelineFactory;
|
|
23
|
+
default?: {
|
|
24
|
+
pipeline?: PipelineFactory;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
28
|
+
/** BGE was trained with CLS pooling; everything else gets mean, the sentence-transformers default, since CLS degrades mean-trained models. */
|
|
29
|
+
export declare function poolingFor(model: string): 'cls' | 'mean';
|
|
30
|
+
/** `query` is search input, `passage` is a document being indexed; no role means no prefix on any model. */
|
|
31
|
+
export type EmbeddingRole = 'query' | 'passage';
|
|
32
|
+
/** e5 models only match a query to a passage when each side carries its trained prefix. */
|
|
33
|
+
export declare function prefixFor(model: string, role?: EmbeddingRole): string;
|
|
34
|
+
/** The optional package as the local embedder reaches it; tests hand in a stand-in. */
|
|
35
|
+
export interface LocalTransformers {
|
|
36
|
+
/** Whether a package is installed, answered without importing it. */
|
|
37
|
+
installed(): boolean;
|
|
38
|
+
/** The package's module, or null when neither package is installed. */
|
|
39
|
+
load(): Promise<{
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly mod: TransformersModule;
|
|
42
|
+
} | null>;
|
|
43
|
+
}
|
|
44
|
+
export interface LocalEmbedder {
|
|
45
|
+
isAvailable(): boolean;
|
|
46
|
+
/** Throws, with the reason, when the model's pipeline cannot load: a provider-level failure, not a per-item skip.
|
|
47
|
+
* `signal` ends the wait, never the load, and only once the load is downloading: a load from disk ends soon on its own, a download may not. */
|
|
48
|
+
requirePipeline(model: string, signal?: AbortSignal): Promise<void>;
|
|
49
|
+
/** `text`'s vector, or `[]` when the model is missing or fails; `role` adds e5-style prefixes. */
|
|
50
|
+
embed(text: string, model: string, role?: EmbeddingRole): Promise<number[]>;
|
|
51
|
+
}
|
|
52
|
+
/** One pipeline per model for the embedder's life, since a pipeline is expensive to load. */
|
|
53
|
+
export declare function createLocalEmbedder(transformers?: LocalTransformers): LocalEmbedder;
|
|
54
|
+
/** The process's embedder, shared by every provider and caller so each model loads once. */
|
|
55
|
+
export declare const sharedLocalEmbedder: LocalEmbedder;
|
|
56
|
+
/** Check (synchronously) if @xenova/transformers or @huggingface/transformers is installed. */
|
|
57
|
+
export declare function isEmbeddingAvailable(): boolean;
|
|
58
|
+
export declare function resolveEmbeddingModel(hippoRoot: string, explicitModel?: string): string;
|
|
59
|
+
/** Embeds `text` with the local model, or returns `[]` when Transformers.js is missing or fails; `role` adds e5-style prefixes. */
|
|
60
|
+
export declare function getEmbedding(text: string, model?: string, role?: EmbeddingRole): Promise<number[]>;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// The local Transformers.js embedder, a leaf so provider.ts can wrap it without importing index.ts.
|
|
2
|
+
import { MINUTE_MS } from '../util/time.js';
|
|
3
|
+
import { envModelCache } from '../util/env.js';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { loadConfig } from '../core/config.js';
|
|
7
|
+
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
8
|
+
import { createModelLoads, importTransformers, MODEL_LOAD_POLICY, resolveTransformersPackage } from './transformers.js';
|
|
9
|
+
export const DEFAULT_EMBEDDING_MODEL = 'Xenova/all-MiniLM-L6-v2';
|
|
10
|
+
/** BGE was trained with CLS pooling; everything else gets mean, the sentence-transformers default, since CLS degrades mean-trained models. */
|
|
11
|
+
export function poolingFor(model) {
|
|
12
|
+
return /\bbge\b/i.test(model) ? 'cls' : 'mean';
|
|
13
|
+
}
|
|
14
|
+
/** e5 models only match a query to a passage when each side carries its trained prefix. */
|
|
15
|
+
export function prefixFor(model, role) {
|
|
16
|
+
if (!role)
|
|
17
|
+
return '';
|
|
18
|
+
if (/\be5\b/i.test(model)) {
|
|
19
|
+
return role === 'query' ? 'query: ' : 'passage: ';
|
|
20
|
+
}
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
const INSTALLED_TRANSFORMERS = {
|
|
24
|
+
installed: () => resolveTransformersPackage() !== null,
|
|
25
|
+
load: () => importTransformers(),
|
|
26
|
+
};
|
|
27
|
+
/** One pipeline per model for the embedder's life, since a pipeline is expensive to load. */
|
|
28
|
+
export function createLocalEmbedder(transformers = INSTALLED_TRANSFORMERS) {
|
|
29
|
+
let available = null;
|
|
30
|
+
const gates = new Map();
|
|
31
|
+
const pipelines = createModelLoads(MODEL_LOAD_POLICY, warnLoadFailure);
|
|
32
|
+
const load = (model) => pipelines.load(model, () => createPipeline(transformers, model, gates));
|
|
33
|
+
const isAvailable = () => (available ??= transformers.installed());
|
|
34
|
+
return {
|
|
35
|
+
isAvailable,
|
|
36
|
+
requirePipeline: (model, signal) => waitForPipeline(load(model), signal && gateOf(gates, model).opened, signal),
|
|
37
|
+
async embed(text, model, role) {
|
|
38
|
+
if (!isAvailable())
|
|
39
|
+
return [];
|
|
40
|
+
try {
|
|
41
|
+
const pipe = await load(model);
|
|
42
|
+
const prefix = prefixFor(model, role);
|
|
43
|
+
const output = await pipe(prefix ? `${prefix}${text}` : text, { pooling: poolingFor(model), normalize: true });
|
|
44
|
+
return Array.from(output.data);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// The caller sees `[]` and names the memory; a failed load already warned once for its backoff window.
|
|
48
|
+
log.debug(`local embedding failed: ${errorMessage(err)}`);
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function warnLoadFailure(model, err) {
|
|
55
|
+
const retry = `the next try is in ${MODEL_LOAD_POLICY.backoffMs / MINUTE_MS} minutes`;
|
|
56
|
+
log.warn(`local embedding model ${model} did not load (${errorMessage(err)}); embeddings stay off and ${retry}`, errorFields(err));
|
|
57
|
+
}
|
|
58
|
+
/** The model's pipeline; throws the reason it cannot load. */
|
|
59
|
+
async function createPipeline(transformers, model, gates) {
|
|
60
|
+
// The package is an optional peer, so the dynamic import is typed by what this file reads; a missing export throws below.
|
|
61
|
+
const imported = await transformers.load();
|
|
62
|
+
if (!imported)
|
|
63
|
+
throw new Error('no transformers package is installed');
|
|
64
|
+
const { name, mod } = imported;
|
|
65
|
+
const cache = envModelCache();
|
|
66
|
+
if (cache && mod.env) {
|
|
67
|
+
mod.env.cacheDir = cache;
|
|
68
|
+
mod.env.localModelPath = cache;
|
|
69
|
+
mod.env.allowRemoteModels = false;
|
|
70
|
+
}
|
|
71
|
+
const pipelineFn = mod.pipeline ?? mod.default?.pipeline;
|
|
72
|
+
if (!pipelineFn)
|
|
73
|
+
throw new Error(`${name} exports no pipeline function`);
|
|
74
|
+
// The offline bundle used in egress-blocked sandboxes ships only the FP32 model, so use whichever file is on disk.
|
|
75
|
+
const quantized = !cache || fs.existsSync(path.join(cache, model, 'onnx', 'model_quantized.onnx'));
|
|
76
|
+
if (fetchesWeights(mod.env, model))
|
|
77
|
+
gateOf(gates, model).open();
|
|
78
|
+
try {
|
|
79
|
+
return await pipelineFn('feature-extraction', model, { quantized });
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
gates.delete(model);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Whether the load will download: remote models are allowed and no folder the package reads holds the model's ONNX files. */
|
|
86
|
+
function fetchesWeights(env, model) {
|
|
87
|
+
if (env?.allowRemoteModels === false)
|
|
88
|
+
return false;
|
|
89
|
+
return ![env?.localModelPath, env?.cacheDir].some((dir) => dir !== undefined && fs.existsSync(path.join(dir, model, 'onnx')));
|
|
90
|
+
}
|
|
91
|
+
function gateOf(gates, model) {
|
|
92
|
+
let gate = gates.get(model);
|
|
93
|
+
if (!gate) {
|
|
94
|
+
let open;
|
|
95
|
+
const opened = new Promise((resolve) => {
|
|
96
|
+
open = resolve;
|
|
97
|
+
});
|
|
98
|
+
gate = { opened, open };
|
|
99
|
+
gates.set(model, gate);
|
|
100
|
+
}
|
|
101
|
+
return gate;
|
|
102
|
+
}
|
|
103
|
+
function rejectOnAbort(signal) {
|
|
104
|
+
return new Promise((_resolve, reject) => {
|
|
105
|
+
if (signal.aborted)
|
|
106
|
+
reject(signal.reason);
|
|
107
|
+
else
|
|
108
|
+
signal.addEventListener('abort', () => reject(signal.reason), { once: true });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async function waitForPipeline(loading, downloading, signal) {
|
|
112
|
+
try {
|
|
113
|
+
await (downloading && signal ? Promise.race([loading, downloading.then(() => rejectOnAbort(signal))]) : loading);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// The download goes on, and the first call after it lands gets the model.
|
|
117
|
+
if (signal?.aborted && err === signal.reason)
|
|
118
|
+
throw err;
|
|
119
|
+
throw new Error(`local embedding model did not load: ${errorMessage(err)}`, { cause: err });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** The process's embedder, shared by every provider and caller so each model loads once. */
|
|
123
|
+
export const sharedLocalEmbedder = createLocalEmbedder();
|
|
124
|
+
/** Check (synchronously) if @xenova/transformers or @huggingface/transformers is installed. */
|
|
125
|
+
export function isEmbeddingAvailable() {
|
|
126
|
+
return sharedLocalEmbedder.isAvailable();
|
|
127
|
+
}
|
|
128
|
+
export function resolveEmbeddingModel(hippoRoot, explicitModel) {
|
|
129
|
+
const direct = explicitModel?.trim();
|
|
130
|
+
if (direct)
|
|
131
|
+
return direct;
|
|
132
|
+
try {
|
|
133
|
+
const configured = loadConfig(hippoRoot).embeddings.model?.trim();
|
|
134
|
+
if (configured)
|
|
135
|
+
return configured;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
log.warn(`embedding model config unreadable, using the default model: ${errorMessage(err)}`);
|
|
139
|
+
}
|
|
140
|
+
return DEFAULT_EMBEDDING_MODEL;
|
|
141
|
+
}
|
|
142
|
+
/** Embeds `text` with the local model, or returns `[]` when Transformers.js is missing or fails; `role` adds e5-style prefixes. */
|
|
143
|
+
export function getEmbedding(text, model = DEFAULT_EMBEDDING_MODEL, role) {
|
|
144
|
+
return sharedLocalEmbedder.embed(text, model, role);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/** Pluggable embedding providers; local `@huggingface/transformers` is the zero-dependency default, OpenAI / Voyage / Cohere are opt-in via native `fetch`.
|
|
2
2
|
* Local `id` is the bare model string, API `id` is `${kind}:${model}`; the stored identity adds `#t<N>` (`embeddingIndexIdentity`), so changes reindex.
|
|
3
3
|
* `embed()` MAY throw on hard transport/auth failure so a reindex aborts atomically; hot paths wrap it and fall back to BM25. */
|
|
4
|
-
import { type EmbeddingRole } from './local.js';
|
|
4
|
+
import { type EmbeddingRole, type LocalTransformers } from './local.js';
|
|
5
5
|
export type EmbeddingProviderKind = 'local' | 'openai' | 'voyage' | 'cohere';
|
|
6
6
|
export declare const API_PROVIDER_KINDS: readonly EmbeddingProviderKind[];
|
|
7
7
|
export interface EmbedCallOptions {
|
|
8
|
-
/** Ends the whole call when it aborts, every batch and retry included. The local provider
|
|
8
|
+
/** Ends the whole call when it aborts, every batch and retry included. The local provider stops waiting only on a model download,
|
|
9
|
+
* since nothing stops a load from disk or an in-process inference. */
|
|
9
10
|
signal?: AbortSignal;
|
|
10
11
|
}
|
|
11
12
|
export interface EmbeddingProvider {
|
|
@@ -28,6 +29,8 @@ export interface ResolveProviderOptions {
|
|
|
28
29
|
model?: string;
|
|
29
30
|
/** Explicit provider override (mainly for tests). */
|
|
30
31
|
provider?: EmbeddingProviderKind;
|
|
32
|
+
/** The Transformers.js package a local provider loads from, with its own models; the process's shared embedder when unset. */
|
|
33
|
+
transformers?: LocalTransformers;
|
|
31
34
|
}
|
|
32
35
|
/** Build the active embedding provider from config (or an explicit override). A missing key never throws here (it surfaces via `isAvailable()`);
|
|
33
36
|
* only an invalid config (e.g. insecure apiBaseUrl) throws, deliberately loud, so hot-path callers wrap it. */
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/** Pluggable embedding providers; local `@huggingface/transformers` is the zero-dependency default, OpenAI / Voyage / Cohere are opt-in via native `fetch`.
|
|
2
2
|
* Local `id` is the bare model string, API `id` is `${kind}:${model}`; the stored identity adds `#t<N>` (`embeddingIndexIdentity`), so changes reindex.
|
|
3
3
|
* `embed()` MAY throw on hard transport/auth failure so a reindex aborts atomically; hot paths wrap it and fall back to BM25. */
|
|
4
|
-
import { envByName } from '
|
|
5
|
-
import {
|
|
6
|
-
import { loadConfig } from '
|
|
7
|
-
import { errorMessage, log } from '
|
|
8
|
-
import { redactSecretsStrict } from '
|
|
9
|
-
import { fetchWithRetry } from '
|
|
10
|
-
import { readCappedJson, readCappedText } from '
|
|
4
|
+
import { envByName } from '../util/env.js';
|
|
5
|
+
import { createLocalEmbedder, resolveEmbeddingModel, sharedLocalEmbedder, DEFAULT_EMBEDDING_MODEL, } from './local.js';
|
|
6
|
+
import { loadConfig } from '../core/config.js';
|
|
7
|
+
import { errorMessage, log } from '../util/log.js';
|
|
8
|
+
import { redactSecretsStrict } from '../util/secret-detect.js';
|
|
9
|
+
import { fetchWithRetry } from '../util/http-retry.js';
|
|
10
|
+
import { readCappedJson, readCappedText } from '../util/capped-json.js';
|
|
11
11
|
const ERROR_DETAIL_CHARS = 300;
|
|
12
12
|
// An error body is read for its first lines only; 4x leaves room for multi-byte text.
|
|
13
13
|
const ERROR_BODY_MAX_BYTES = ERROR_DETAIL_CHARS * 4;
|
|
@@ -27,24 +27,26 @@ const DEADLINE_RETRY_WAIT_CAP_MS = 2_000;
|
|
|
27
27
|
class LocalEmbeddingProvider {
|
|
28
28
|
model;
|
|
29
29
|
enabled;
|
|
30
|
+
embedder;
|
|
30
31
|
kind = 'local';
|
|
31
|
-
constructor(model, enabled
|
|
32
|
+
constructor(model, enabled, embedder) {
|
|
32
33
|
this.model = model;
|
|
33
34
|
this.enabled = enabled;
|
|
35
|
+
this.embedder = embedder;
|
|
34
36
|
}
|
|
35
37
|
get id() {
|
|
36
38
|
return this.model;
|
|
37
39
|
}
|
|
38
40
|
isAvailable() {
|
|
39
|
-
return this.enabled &&
|
|
41
|
+
return this.enabled && this.embedder.isAvailable();
|
|
40
42
|
}
|
|
41
|
-
async embed(texts, role) {
|
|
43
|
+
async embed(texts, role, call = {}) {
|
|
42
44
|
// A model that cannot load fails the call, as an API outage does; items then run one at a time on the shared pipeline.
|
|
43
45
|
if (texts.length > 0)
|
|
44
|
-
await
|
|
46
|
+
await this.embedder.requirePipeline(this.model, call.signal);
|
|
45
47
|
const out = [];
|
|
46
48
|
for (const text of texts) {
|
|
47
|
-
out.push(await
|
|
49
|
+
out.push(await this.embedder.embed(text, this.model, role));
|
|
48
50
|
}
|
|
49
51
|
return out;
|
|
50
52
|
}
|
|
@@ -211,8 +213,8 @@ class ApiEmbeddingProvider {
|
|
|
211
213
|
try {
|
|
212
214
|
detail = await readCappedText(resp, ERROR_BODY_MAX_BYTES);
|
|
213
215
|
}
|
|
214
|
-
catch {
|
|
215
|
-
|
|
216
|
+
catch (err) {
|
|
217
|
+
log.debug(`${this.kind} embeddings error body unreadable: ${errorMessage(err)}`);
|
|
216
218
|
}
|
|
217
219
|
throw new Error(redact(`${this.kind} embeddings HTTP ${resp.status}: ${detail.slice(0, ERROR_DETAIL_CHARS)}`, key));
|
|
218
220
|
}
|
|
@@ -264,7 +266,8 @@ export function resolveEmbeddingProvider(hippoRoot, opts = {}) {
|
|
|
264
266
|
// and API providers — for API this prevents unwanted paid off-box calls.
|
|
265
267
|
const enabled = cfg.enabled !== false;
|
|
266
268
|
if (requested === 'local') {
|
|
267
|
-
|
|
269
|
+
const embedder = opts.transformers ? createLocalEmbedder(opts.transformers) : sharedLocalEmbedder;
|
|
270
|
+
return new LocalEmbeddingProvider(resolveEmbeddingModel(hippoRoot, opts.model), enabled, embedder);
|
|
268
271
|
}
|
|
269
272
|
if (!isApiProviderKind(requested)) {
|
|
270
273
|
// Fail loud on a typo'd provider rather than silently using local (which
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface TransformersPackage {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
/** The ESM entry; a require-style import picks the CommonJS build and puts a second copy of the library, with its own ONNX sessions, in the process. */
|
|
4
|
+
readonly url: string;
|
|
5
|
+
}
|
|
6
|
+
/** The installed package to import, or null when neither is installed. */
|
|
7
|
+
export declare function resolveTransformersPackage(): TransformersPackage | null;
|
|
8
|
+
/** The package's module namespace, typed by the parts the caller reads; null when neither package is installed. */
|
|
9
|
+
export declare function importTransformers<M>(): Promise<{
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly mod: M;
|
|
12
|
+
} | null>;
|
|
13
|
+
export interface ModelLoadPolicy {
|
|
14
|
+
/** How long one load may run before it counts as failed; nothing can cancel it, so it keeps running and a late model is still kept. */
|
|
15
|
+
readonly timeoutMs: number;
|
|
16
|
+
/** How long a failure is answered from memory before the next call loads again. */
|
|
17
|
+
readonly backoffMs: number;
|
|
18
|
+
}
|
|
19
|
+
export declare const MODEL_LOAD_POLICY: ModelLoadPolicy;
|
|
20
|
+
export interface ModelLoads<T> {
|
|
21
|
+
/** The model under `key`: the loaded one, the load in flight, the failure inside its backoff window, or a new `start()`. */
|
|
22
|
+
load(key: string, start: () => Promise<T>): Promise<T>;
|
|
23
|
+
}
|
|
24
|
+
/** One load per key at a time, bounded by the policy's timeout; `onFailure` hears each failed attempt, so once per backoff window. */
|
|
25
|
+
export declare function createModelLoads<T>(policy: ModelLoadPolicy, onFailure?: (key: string, err: Error) => void): ModelLoads<T>;
|
|
26
|
+
//# sourceMappingURL=transformers.d.ts.map
|