hippo-memory 1.60.0 → 1.62.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 +29 -54
- package/dist/ablation.js +9 -27
- package/dist/agent-memories/apply.d.ts +1 -1
- package/dist/agent-memories/apply.js +4 -1
- package/dist/agent-memories/claude-code.d.ts +3 -1
- package/dist/agent-memories/claude-code.js +54 -10
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/gemini.js +1 -1
- package/dist/agent-memories/legacy.js +1 -1
- package/dist/agent-memories/source.js +1 -1
- package/dist/agent-memories/sync.d.ts +3 -3
- package/dist/agent-memories/sync.js +22 -9
- package/dist/agent-memories/types.d.ts +0 -2
- package/dist/ambient-store.d.ts +14 -0
- package/dist/ambient-store.js +90 -0
- package/dist/ambient.d.ts +23 -0
- package/dist/ambient.js +72 -50
- package/dist/api/assemble.d.ts +93 -0
- package/dist/api/assemble.js +153 -0
- package/dist/api/audit.d.ts +17 -0
- package/dist/api/audit.js +23 -0
- package/dist/api/auth.d.ts +79 -0
- package/dist/api/auth.js +178 -0
- package/dist/api/context-select.d.ts +49 -0
- package/dist/api/context-select.js +344 -0
- package/dist/api/context-types.d.ts +105 -0
- package/dist/api/context-types.js +3 -0
- package/dist/api/context.d.ts +31 -0
- package/dist/api/context.js +378 -0
- package/dist/api/dormant.d.ts +30 -0
- package/dist/api/dormant.js +140 -0
- package/dist/api/drill-down.d.ts +84 -0
- package/dist/api/drill-down.js +126 -0
- package/dist/api/forget.d.ts +57 -0
- package/dist/api/forget.js +87 -0
- package/dist/api/goals.d.ts +18 -0
- package/dist/api/goals.js +33 -0
- package/dist/api/learn.d.ts +31 -0
- package/dist/api/learn.js +88 -0
- package/dist/api/outcome.d.ts +61 -0
- package/dist/api/outcome.js +66 -0
- package/dist/api/promote.d.ts +54 -0
- package/dist/api/promote.js +192 -0
- package/dist/api/quarantine.d.ts +24 -0
- package/dist/api/quarantine.js +121 -0
- package/dist/api/recall-types.d.ts +390 -0
- package/dist/api/recall-types.js +3 -0
- package/dist/api/recall.d.ts +36 -0
- package/dist/api/recall.js +499 -0
- package/dist/api/remember.d.ts +35 -0
- package/dist/api/remember.js +43 -0
- package/dist/api/sleep.d.ts +136 -0
- package/dist/api/sleep.js +256 -0
- package/dist/api/tokens.d.ts +26 -0
- package/dist/api/tokens.js +60 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/api/types.js +38 -0
- package/dist/api.d.ts +20 -1262
- package/dist/api.js +25 -2727
- package/dist/audit.d.ts +3 -0
- package/dist/audit.js +6 -3
- package/dist/auth.d.ts +45 -4
- package/dist/auth.js +125 -48
- package/dist/autolearn.js +2 -2
- package/dist/capture/command.d.ts +33 -0
- package/dist/capture/command.js +264 -0
- package/dist/capture/compact.d.ts +44 -0
- package/dist/capture/compact.js +354 -0
- package/dist/capture/extract.d.ts +21 -0
- package/dist/capture/extract.js +464 -0
- package/dist/capture/transcript.d.ts +40 -0
- package/dist/capture/transcript.js +193 -0
- package/dist/capture-error.js +2 -1
- package/dist/churn-git.js +4 -2
- package/dist/cli/audit.d.ts +3 -0
- package/dist/cli/audit.js +159 -0
- package/dist/cli/auth.d.ts +2 -0
- package/dist/cli/auth.js +171 -0
- package/dist/cli/briefs.d.ts +4 -0
- package/dist/cli/briefs.js +453 -0
- package/dist/cli/card.d.ts +3 -0
- package/dist/cli/card.js +333 -0
- package/dist/cli/context.d.ts +15 -0
- package/dist/cli/context.js +376 -0
- package/dist/cli/continuity.d.ts +6 -0
- package/dist/cli/continuity.js +457 -0
- package/dist/cli/curate.d.ts +19 -0
- package/dist/cli/curate.js +556 -0
- package/dist/cli/dag.d.ts +5 -0
- package/dist/cli/dag.js +177 -0
- package/dist/cli/decisions.d.ts +4 -0
- package/dist/cli/decisions.js +528 -0
- package/dist/cli/eval.d.ts +5 -0
- package/dist/cli/eval.js +213 -0
- package/dist/cli/explain.d.ts +4 -0
- package/dist/cli/explain.js +156 -0
- package/dist/cli/goals.d.ts +2 -0
- package/dist/cli/goals.js +196 -0
- package/dist/cli/hook-blocks.d.ts +18 -0
- package/dist/cli/hook-blocks.js +233 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +305 -0
- package/dist/cli/maintenance.d.ts +4 -0
- package/dist/cli/maintenance.js +190 -0
- package/dist/cli/playbooks.d.ts +4 -0
- package/dist/cli/playbooks.js +573 -0
- package/dist/cli/projects.js +9 -6
- package/dist/cli/recall.d.ts +7 -0
- package/dist/cli/recall.js +582 -0
- package/dist/cli/remember.d.ts +5 -0
- package/dist/cli/remember.js +485 -0
- package/dist/cli/serve.d.ts +5 -0
- package/dist/cli/serve.js +40 -0
- package/dist/cli/session-hooks.d.ts +29 -0
- package/dist/cli/session-hooks.js +647 -0
- package/dist/cli/setup.d.ts +4 -0
- package/dist/cli/setup.js +397 -0
- package/dist/cli/shared.d.ts +15 -19
- package/dist/cli/shared.js +50 -341
- package/dist/cli/slack.d.ts +2 -0
- package/dist/cli/slack.js +171 -0
- package/dist/cli/status.d.ts +18 -0
- package/dist/cli/status.js +409 -0
- package/dist/cli/transfer.d.ts +10 -0
- package/dist/cli/transfer.js +424 -0
- package/dist/cli/usage.d.ts +85 -0
- package/dist/cli/usage.js +741 -0
- package/dist/cli.d.ts +71 -120
- package/dist/cli.js +170 -8469
- package/dist/client.js +15 -8
- package/dist/compaction-record.d.ts +0 -2
- package/dist/compaction-record.js +7 -5
- package/dist/connectors/github/backfill.js +94 -87
- package/dist/connectors/github/cli-impl.js +4 -3
- package/dist/connectors/github/dlq.js +67 -54
- package/dist/connectors/github/ingest.js +34 -35
- package/dist/connectors/github/tenant-routing.js +3 -2
- package/dist/connectors/github/webhook.js +135 -216
- package/dist/connectors/slack/dlq.js +49 -61
- package/dist/connectors/slack/ingest.js +55 -48
- package/dist/connectors/slack/tenant-routing.js +4 -3
- package/dist/connectors/slack/webhook.js +72 -74
- package/dist/consolidate/conflicts.d.ts +10 -0
- package/dist/consolidate/conflicts.js +178 -0
- package/dist/consolidate/decay.d.ts +12 -0
- package/dist/consolidate/decay.js +145 -0
- package/dist/consolidate/llm-passes.d.ts +3 -0
- package/dist/consolidate/llm-passes.js +141 -0
- package/dist/consolidate/merge.d.ts +7 -0
- package/dist/consolidate/merge.js +251 -0
- package/dist/consolidate/physics-pass.d.ts +3 -0
- package/dist/consolidate/physics-pass.js +60 -0
- package/dist/consolidate/run.d.ts +69 -0
- package/dist/consolidate/run.js +76 -0
- package/dist/consolidate/sleep.d.ts +18 -0
- package/dist/consolidate/sleep.js +209 -0
- package/dist/consolidate/traces.d.ts +4 -0
- package/dist/consolidate/traces.js +178 -0
- package/dist/context-auto.js +7 -11
- package/dist/context-render.d.ts +1 -1
- package/dist/context-render.js +1 -1
- package/dist/customer-notes.d.ts +3 -0
- package/dist/customer-notes.js +83 -72
- package/dist/dag.js +225 -188
- package/dist/dashboard-actions.d.ts +20 -0
- package/dist/dashboard-actions.js +88 -0
- package/dist/dashboard-params.d.ts +45 -0
- package/dist/dashboard-params.js +127 -0
- package/dist/dashboard-queries.d.ts +15 -0
- package/dist/dashboard-queries.js +355 -0
- package/dist/dashboard-snapshot.d.ts +138 -0
- package/dist/dashboard-snapshot.js +308 -0
- package/dist/dashboard-types.d.ts +163 -0
- package/dist/dashboard-types.js +3 -0
- package/dist/dashboard.d.ts +6 -7
- package/dist/dashboard.js +228 -202
- package/dist/db/busy.d.ts +5 -0
- package/dist/db/busy.js +24 -0
- package/dist/db/continuity.d.ts +5 -0
- package/dist/db/continuity.js +145 -0
- package/dist/db/meta.d.ts +8 -0
- package/dist/db/meta.js +35 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.js +138 -0
- package/dist/db/migrations/index.d.ts +5 -0
- package/dist/db/migrations/index.js +109 -0
- package/dist/db/migrations/types.d.ts +14 -0
- package/dist/db/migrations/types.js +2 -0
- package/dist/db/migrations/v01.d.ts +3 -0
- package/dist/db/migrations/v01.js +38 -0
- package/dist/db/migrations/v02.d.ts +3 -0
- package/dist/db/migrations/v02.js +21 -0
- package/dist/db/migrations/v03.d.ts +3 -0
- package/dist/db/migrations/v03.js +22 -0
- package/dist/db/migrations/v04.d.ts +3 -0
- package/dist/db/migrations/v04.js +28 -0
- package/dist/db/migrations/v05.d.ts +3 -0
- package/dist/db/migrations/v05.js +21 -0
- package/dist/db/migrations/v06.d.ts +3 -0
- package/dist/db/migrations/v06.js +25 -0
- package/dist/db/migrations/v07.d.ts +3 -0
- package/dist/db/migrations/v07.js +13 -0
- package/dist/db/migrations/v08.d.ts +3 -0
- package/dist/db/migrations/v08.js +8 -0
- package/dist/db/migrations/v09.d.ts +3 -0
- package/dist/db/migrations/v09.js +13 -0
- package/dist/db/migrations/v10.d.ts +3 -0
- package/dist/db/migrations/v10.js +17 -0
- package/dist/db/migrations/v11.d.ts +3 -0
- package/dist/db/migrations/v11.js +15 -0
- package/dist/db/migrations/v12.d.ts +3 -0
- package/dist/db/migrations/v12.js +11 -0
- package/dist/db/migrations/v13.d.ts +3 -0
- package/dist/db/migrations/v13.js +15 -0
- package/dist/db/migrations/v14.d.ts +3 -0
- package/dist/db/migrations/v14.js +66 -0
- package/dist/db/migrations/v15.d.ts +3 -0
- package/dist/db/migrations/v15.js +42 -0
- package/dist/db/migrations/v16.d.ts +3 -0
- package/dist/db/migrations/v16.js +61 -0
- package/dist/db/migrations/v17.d.ts +3 -0
- package/dist/db/migrations/v17.js +46 -0
- package/dist/db/migrations/v18.d.ts +3 -0
- package/dist/db/migrations/v18.js +60 -0
- package/dist/db/migrations/v19.d.ts +3 -0
- package/dist/db/migrations/v19.js +28 -0
- package/dist/db/migrations/v20.d.ts +3 -0
- package/dist/db/migrations/v20.js +42 -0
- package/dist/db/migrations/v21.d.ts +3 -0
- package/dist/db/migrations/v21.js +16 -0
- package/dist/db/migrations/v22.d.ts +3 -0
- package/dist/db/migrations/v22.js +82 -0
- package/dist/db/migrations/v23.d.ts +3 -0
- package/dist/db/migrations/v23.js +48 -0
- package/dist/db/migrations/v24.d.ts +3 -0
- package/dist/db/migrations/v24.js +72 -0
- package/dist/db/migrations/v25.d.ts +3 -0
- package/dist/db/migrations/v25.js +46 -0
- package/dist/db/migrations/v26.d.ts +3 -0
- package/dist/db/migrations/v26.js +23 -0
- package/dist/db/migrations/v27.d.ts +3 -0
- package/dist/db/migrations/v27.js +57 -0
- package/dist/db/migrations/v28.d.ts +3 -0
- package/dist/db/migrations/v28.js +38 -0
- package/dist/db/migrations/v29.d.ts +3 -0
- package/dist/db/migrations/v29.js +78 -0
- package/dist/db/migrations/v30.d.ts +3 -0
- package/dist/db/migrations/v30.js +92 -0
- package/dist/db/migrations/v31.d.ts +3 -0
- package/dist/db/migrations/v31.js +74 -0
- package/dist/db/migrations/v32.d.ts +3 -0
- package/dist/db/migrations/v32.js +102 -0
- package/dist/db/migrations/v33.d.ts +3 -0
- package/dist/db/migrations/v33.js +104 -0
- package/dist/db/migrations/v34.d.ts +3 -0
- package/dist/db/migrations/v34.js +93 -0
- package/dist/db/migrations/v35.d.ts +3 -0
- package/dist/db/migrations/v35.js +98 -0
- package/dist/db/migrations/v36.d.ts +3 -0
- package/dist/db/migrations/v36.js +98 -0
- package/dist/db/migrations/v37.d.ts +3 -0
- package/dist/db/migrations/v37.js +219 -0
- package/dist/db/migrations/v38.d.ts +3 -0
- package/dist/db/migrations/v38.js +277 -0
- package/dist/db/migrations/v39.d.ts +3 -0
- package/dist/db/migrations/v39.js +59 -0
- package/dist/db/migrations/v40.d.ts +3 -0
- package/dist/db/migrations/v40.js +74 -0
- package/dist/db/migrations/v41.d.ts +3 -0
- package/dist/db/migrations/v41.js +43 -0
- package/dist/db/migrations/v42.d.ts +3 -0
- package/dist/db/migrations/v42.js +41 -0
- package/dist/db/migrations/v43.d.ts +3 -0
- package/dist/db/migrations/v43.js +67 -0
- package/dist/db/migrations/v44.d.ts +3 -0
- package/dist/db/migrations/v44.js +28 -0
- package/dist/db/migrations/v45.d.ts +3 -0
- package/dist/db/migrations/v45.js +30 -0
- package/dist/db/migrations/v46.d.ts +3 -0
- package/dist/db/migrations/v46.js +25 -0
- package/dist/db/migrations/v47.d.ts +3 -0
- package/dist/db/migrations/v47.js +17 -0
- package/dist/db/migrations/v48.d.ts +3 -0
- package/dist/db/migrations/v48.js +10 -0
- package/dist/db/migrations/v49.d.ts +3 -0
- package/dist/db/migrations/v49.js +31 -0
- package/dist/db/migrations/v50.d.ts +3 -0
- package/dist/db/migrations/v50.js +67 -0
- package/dist/db/migrations/v51.d.ts +3 -0
- package/dist/db/migrations/v51.js +14 -0
- package/dist/db/migrations/v52.d.ts +3 -0
- package/dist/db/migrations/v52.js +7 -0
- package/dist/db/open.d.ts +23 -0
- package/dist/db/open.js +146 -0
- package/dist/db/sqlite.d.ts +21 -0
- package/dist/db/sqlite.js +8 -0
- package/dist/db/tables.d.ts +7 -0
- package/dist/db/tables.js +38 -0
- package/dist/db.d.ts +6 -46
- package/dist/db.js +5 -3049
- package/dist/decisions.d.ts +4 -1
- package/dist/decisions.js +102 -83
- package/dist/dedupe.js +3 -2
- package/dist/delivery-recorder.js +4 -1
- package/dist/doctor.js +14 -10
- package/dist/embedding-provider.d.ts +1 -1
- package/dist/embedding-provider.js +4 -3
- package/dist/embeddings.d.ts +9 -52
- package/dist/embeddings.js +43 -297
- package/dist/env.d.ts +75 -0
- package/dist/env.js +119 -0
- package/dist/eval-suite.js +1 -1
- package/dist/eval.js +2 -2
- package/dist/extract.js +1 -1
- package/dist/gated-write.js +3 -1
- package/dist/goals.d.ts +3 -1
- package/dist/goals.js +117 -86
- package/dist/graph/read.d.ts +73 -0
- package/dist/graph/read.js +325 -0
- package/dist/graph/rows.d.ts +45 -0
- package/dist/graph/rows.js +51 -0
- package/dist/graph/types.d.ts +83 -0
- package/dist/graph/types.js +11 -0
- package/dist/graph/write.d.ts +93 -0
- package/dist/{graph.js → graph/write.js} +6 -384
- package/dist/graph-extract.js +2 -1
- package/dist/graph-recall.d.ts +1 -1
- package/dist/graph-recall.js +2 -2
- package/dist/graph-stream.js +1 -1
- package/dist/graph-view.d.ts +1 -1
- package/dist/graph-view.js +1 -1
- package/dist/half-life-migration.d.ts +1 -1
- package/dist/half-life-migration.js +2 -1
- package/dist/hooks/codex-session.d.ts +8 -0
- package/dist/hooks/codex-session.js +76 -0
- package/dist/hooks/codex-wrapper.d.ts +55 -0
- package/dist/hooks/codex-wrapper.js +288 -0
- package/dist/hooks/json-hooks.d.ts +63 -0
- package/dist/hooks/json-hooks.js +356 -0
- package/dist/hooks/opencode.d.ts +50 -0
- package/dist/hooks/opencode.js +202 -0
- package/dist/hooks/shared.d.ts +54 -0
- package/dist/hooks/shared.js +77 -0
- package/dist/http-retry.d.ts +2 -0
- package/dist/http-retry.js +4 -3
- package/dist/http-util.d.ts +3 -0
- package/dist/http-util.js +10 -0
- package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
- package/dist/importers/core.js +141 -0
- package/dist/importers/markdown-parse.d.ts +41 -0
- package/dist/importers/markdown-parse.js +132 -0
- package/dist/importers/markdown.d.ts +3 -0
- package/dist/importers/markdown.js +92 -0
- package/dist/importers/sources.d.ts +7 -0
- package/dist/importers/sources.js +229 -0
- package/dist/importers/vault.d.ts +11 -0
- package/dist/importers/vault.js +352 -0
- package/dist/incidents.d.ts +3 -0
- package/dist/incidents.js +52 -43
- package/dist/index.d.ts +25 -6
- package/dist/index.js +23 -6
- package/dist/invalidation.js +2 -1
- package/dist/judgment.js +2 -1
- package/dist/keyset.d.ts +13 -0
- package/dist/keyset.js +8 -0
- package/dist/local-embedding.d.ts +13 -0
- package/dist/local-embedding.js +165 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +19 -1
- package/dist/mcp/admin-tools.d.ts +8 -0
- package/dist/mcp/admin-tools.js +116 -0
- package/dist/mcp/format.d.ts +27 -0
- package/dist/mcp/format.js +135 -0
- package/dist/mcp/memory-tools.d.ts +5 -0
- package/dist/mcp/memory-tools.js +83 -0
- package/dist/mcp/protocol.d.ts +83 -0
- package/dist/mcp/protocol.js +55 -0
- package/dist/mcp/recall-tools.d.ts +6 -0
- package/dist/mcp/recall-tools.js +320 -0
- package/dist/mcp/request.d.ts +10 -0
- package/dist/mcp/request.js +163 -0
- package/dist/mcp/server.d.ts +4 -75
- package/dist/mcp/server.js +7 -1190
- package/dist/mcp/session-state.d.ts +11 -0
- package/dist/mcp/session-state.js +28 -0
- package/dist/mcp/stdio.d.ts +8 -0
- package/dist/mcp/stdio.js +79 -0
- package/dist/mcp/tools.d.ts +11 -0
- package/dist/mcp/tools.js +247 -0
- package/dist/memory.d.ts +3 -0
- package/dist/memory.js +27 -1
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +2 -1
- package/dist/owner-validation.js +2 -1
- package/dist/physics-state.js +10 -7
- package/dist/policies.d.ts +3 -0
- package/dist/policies.js +93 -74
- package/dist/postinstall.js +3 -2
- package/dist/predictions/planning-fallacy.d.ts +100 -0
- package/dist/predictions/planning-fallacy.js +190 -0
- package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
- package/dist/predictions/store.js +434 -0
- package/dist/processes.d.ts +3 -0
- package/dist/processes.js +94 -76
- package/dist/project-briefs.d.ts +3 -0
- package/dist/project-briefs.js +142 -113
- package/dist/project-identity.js +3 -2
- package/dist/project-merge.d.ts +12 -4
- package/dist/project-merge.js +132 -45
- package/dist/quarantine.d.ts +2 -1
- package/dist/quarantine.js +8 -5
- package/dist/raw-archive.js +1 -1
- package/dist/recall-history.js +3 -2
- package/dist/recall-pipeline.d.ts +2 -2
- package/dist/recall-pipeline.js +16 -8
- package/dist/recall-scope.js +1 -1
- package/dist/recall-trace.d.ts +1 -1
- package/dist/refine-llm.js +2 -1
- package/dist/reject-flow.js +6 -1
- package/dist/rerankers/clef.js +6 -5
- package/dist/rerankers/jev.d.ts +1 -1
- package/dist/rerankers/jev.js +4 -4
- package/dist/rerankers/llm.d.ts +4 -2
- package/dist/rerankers/llm.js +58 -38
- package/dist/rerankers/types.d.ts +1 -1
- package/dist/salience.js +1 -1
- package/dist/scheduler.d.ts +1 -0
- package/dist/scheduler.js +26 -4
- package/dist/scope.js +4 -3
- package/dist/search/as-of.d.ts +10 -0
- package/dist/search/as-of.js +22 -0
- package/dist/search/bm25-search.d.ts +14 -0
- package/dist/search/bm25-search.js +43 -0
- package/dist/search/bm25.d.ts +15 -0
- package/dist/search/bm25.js +54 -0
- package/dist/search/boosts.d.ts +54 -0
- package/dist/search/boosts.js +94 -0
- package/dist/search/breakdown.d.ts +7 -0
- package/dist/search/breakdown.js +20 -0
- package/dist/search/explain.d.ts +25 -0
- package/dist/search/explain.js +31 -0
- package/dist/search/finalize.d.ts +8 -0
- package/dist/search/finalize.js +52 -0
- package/dist/search/fusion.d.ts +27 -0
- package/dist/search/fusion.js +42 -0
- package/dist/search/hybrid-score.d.ts +20 -0
- package/dist/search/hybrid-score.js +73 -0
- package/dist/search/hybrid.d.ts +46 -0
- package/dist/search/hybrid.js +64 -0
- package/dist/search/physics-search.d.ts +29 -0
- package/dist/search/physics-search.js +162 -0
- package/dist/search/rerank.d.ts +10 -0
- package/dist/search/rerank.js +72 -0
- package/dist/search/temporal.d.ts +15 -0
- package/dist/search/temporal.js +45 -0
- package/dist/search/types.d.ts +91 -0
- package/dist/search/types.js +2 -0
- package/dist/search/vector.d.ts +30 -0
- package/dist/search/vector.js +71 -0
- package/dist/secret-detect.d.ts +2 -0
- package/dist/secret-detect.js +2 -1
- package/dist/server/auth.d.ts +52 -0
- package/dist/server/auth.js +221 -0
- package/dist/server/client-ip.d.ts +25 -0
- package/dist/server/client-ip.js +92 -0
- package/dist/server/cursor.d.ts +23 -0
- package/dist/server/cursor.js +58 -0
- package/dist/server/lifecycle.d.ts +7 -0
- package/dist/server/lifecycle.js +29 -0
- package/dist/server/mcp-http.d.ts +5 -0
- package/dist/server/mcp-http.js +199 -0
- package/dist/server/request.d.ts +33 -0
- package/dist/server/request.js +103 -0
- package/dist/server/routes/admin.d.ts +9 -0
- package/dist/server/routes/admin.js +158 -0
- package/dist/server/routes/customer-notes.d.ts +7 -0
- package/dist/server/routes/customer-notes.js +112 -0
- package/dist/server/routes/decisions.d.ts +7 -0
- package/dist/server/routes/decisions.js +133 -0
- package/dist/server/routes/incidents.d.ts +7 -0
- package/dist/server/routes/incidents.js +126 -0
- package/dist/server/routes/memories.d.ts +10 -0
- package/dist/server/routes/memories.js +179 -0
- package/dist/server/routes/policies.d.ts +8 -0
- package/dist/server/routes/policies.js +151 -0
- package/dist/server/routes/predictions.d.ts +7 -0
- package/dist/server/routes/predictions.js +164 -0
- package/dist/server/routes/processes.d.ts +7 -0
- package/dist/server/routes/processes.js +161 -0
- package/dist/server/routes/project-briefs.d.ts +8 -0
- package/dist/server/routes/project-briefs.js +136 -0
- package/dist/server/routes/recall.d.ts +8 -0
- package/dist/server/routes/recall.js +340 -0
- package/dist/server/routes/skills.d.ts +8 -0
- package/dist/server/routes/skills.js +150 -0
- package/dist/server/types.d.ts +56 -0
- package/dist/server/types.js +2 -0
- package/dist/server/validation.d.ts +14 -0
- package/dist/server/validation.js +91 -0
- package/dist/server.d.ts +7 -61
- package/dist/server.js +69 -2362
- package/dist/session-digest.d.ts +1 -1
- package/dist/session-digest.js +9 -2
- package/dist/shared.d.ts +12 -1
- package/dist/shared.js +33 -27
- package/dist/skills.d.ts +3 -0
- package/dist/skills.js +88 -70
- package/dist/stdin.js +2 -2
- package/dist/store/audit-event.d.ts +19 -0
- package/dist/store/audit-event.js +33 -0
- package/dist/store/candidates.d.ts +42 -0
- package/dist/store/candidates.js +152 -0
- package/dist/store/conflicts.d.ts +44 -0
- package/dist/store/conflicts.js +444 -0
- package/dist/store/delete-and-batch.d.ts +63 -0
- package/dist/store/delete-and-batch.js +310 -0
- package/dist/store/entry-reads.d.ts +92 -0
- package/dist/store/entry-reads.js +255 -0
- package/dist/store/entry-row.d.ts +67 -0
- package/dist/store/entry-row.js +208 -0
- package/dist/store/entry-writes.d.ts +46 -0
- package/dist/store/entry-writes.js +148 -0
- package/dist/store/handoffs.d.ts +26 -0
- package/dist/store/handoffs.js +184 -0
- package/dist/store/index-and-stats.d.ts +52 -0
- package/dist/store/index-and-stats.js +214 -0
- package/dist/store/markdown.d.ts +10 -0
- package/dist/store/markdown.js +108 -0
- package/dist/store/mirrors.d.ts +49 -0
- package/dist/store/mirrors.js +312 -0
- package/dist/store/open.d.ts +15 -0
- package/dist/store/open.js +223 -0
- package/dist/store/rows.d.ts +178 -0
- package/dist/store/rows.js +158 -0
- package/dist/store/search-rows.d.ts +86 -0
- package/dist/store/search-rows.js +260 -0
- package/dist/store/sessions.d.ts +83 -0
- package/dist/store/sessions.js +272 -0
- package/dist/store/summaries.d.ts +94 -0
- package/dist/store/summaries.js +377 -0
- package/dist/store/tenant-lookup.d.ts +12 -0
- package/dist/store/tenant-lookup.js +16 -0
- package/dist/store-cards.js +2 -1
- package/dist/summary-dirty.d.ts +4 -0
- package/dist/summary-dirty.js +32 -0
- package/dist/support-bundle.js +4 -3
- package/dist/tenant.js +2 -2
- package/dist/tokenize.d.ts +2 -0
- package/dist/tokenize.js +16 -0
- package/dist/transcript-tail.d.ts +7 -0
- package/dist/transcript-tail.js +48 -0
- package/dist/vector-store.d.ts +27 -0
- package/dist/vector-store.js +210 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/working-memory.js +1 -1
- package/dist/yaml.js +36 -11
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist-ui/assets/index-DPN7cP19.js +33 -0
- package/dist-ui/assets/index-dFloKRVr.css +1 -0
- package/dist-ui/index.html +3 -25
- 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 +1 -1
- package/dist/capture.d.ts +0 -155
- package/dist/capture.js +0 -1295
- package/dist/consolidate.d.ts +0 -58
- package/dist/consolidate.js +0 -1124
- package/dist/graph.d.ts +0 -245
- package/dist/hooks.d.ts +0 -208
- package/dist/hooks.js +0 -1076
- package/dist/importers.js +0 -900
- package/dist/predictions.js +0 -620
- package/dist/search.d.ts +0 -320
- package/dist/search.js +0 -970
- package/dist/store.d.ts +0 -776
- package/dist/store.js +0 -3473
- package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
- package/dist-ui/assets/index-BhT8RvO6.js +0 -61
- package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
- package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
// Read path: recall (sync) and retrieve (async, adds the vector arm).
|
|
2
|
+
import { envRequireSessionScopedFreshTail } from '../env.js';
|
|
3
|
+
import { openHippoDb, closeHippoDb } from '../db.js';
|
|
4
|
+
import { DEFAULT_SEARCH_CANDIDATE_LIMIT } from '../store/rows.js';
|
|
5
|
+
import { strengthenRetrieved } from '../store/entry-writes.js';
|
|
6
|
+
import { isRecallBoostAblated } from '../ablation.js';
|
|
7
|
+
import { loadEntriesByIds, loadFreshRawMemories } from '../store/entry-reads.js';
|
|
8
|
+
import { loadRecallSearchEntries, recallScopeFilter } from '../store/search-rows.js';
|
|
9
|
+
import { loadActiveTaskSnapshot, listSessionEvents } from '../store/sessions.js';
|
|
10
|
+
import { loadLatestHandoff } from '../store/handoffs.js';
|
|
11
|
+
import { estimateTokens } from '../token-ledger.js';
|
|
12
|
+
import { formatHandoffEvidenceLine } from '../handoff.js';
|
|
13
|
+
import { appendAuditEvent, auditQueryFields } from '../audit.js';
|
|
14
|
+
import { writeRecallTrace, writeRecallTraceAtRoot } from '../recall-trace.js';
|
|
15
|
+
import { applyGoalStackBoost } from '../goals.js';
|
|
16
|
+
import { hybridSearch } from '../search/hybrid.js';
|
|
17
|
+
import { physicsSearch } from '../search/physics-search.js';
|
|
18
|
+
import { churnStaleFactor } from '../search/boosts.js';
|
|
19
|
+
import { compareEntryIdentity } from '../compare.js';
|
|
20
|
+
import { dropHeldCopies, duplicateKey, storedTextKeys } from '../same-text.js';
|
|
21
|
+
import { loadConfig } from '../config.js';
|
|
22
|
+
import { computePlanningFallacyOutput } from '../predictions/planning-fallacy.js';
|
|
23
|
+
import { detectAnchoring, hashQueryText, biasHintEnabled } from '../recall-history.js';
|
|
24
|
+
import { detectAvailabilityBias } from '../availability.js';
|
|
25
|
+
import { passesScopeFilterForRecall, assertScopeRequestAllowed, isRestrictedScope } from '../recall-scope.js';
|
|
26
|
+
import { RecallContractError } from './types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Shared construction helper for `RecallSuppressionSummary`. Used by
|
|
29
|
+
* `api.recall`, `cmdRecall`, and the MCP `hippo_recall` handler so all three
|
|
30
|
+
* pipelines produce the same shape without duplicating field-construction
|
|
31
|
+
* logic. Pass-through identity today; kept as a helper so future field
|
|
32
|
+
* additions (B4 interference counter wiring, etc.) land at one site.
|
|
33
|
+
*/
|
|
34
|
+
export function buildSuppressionSummary(counts) {
|
|
35
|
+
return {
|
|
36
|
+
totalCandidates: counts.totalCandidates,
|
|
37
|
+
droppedPreRank: counts.droppedPreRank,
|
|
38
|
+
droppedByBudget: counts.droppedByBudget,
|
|
39
|
+
summarySubstitutionsAdded: counts.summarySubstitutionsAdded,
|
|
40
|
+
freshTailAdded: counts.freshTailAdded,
|
|
41
|
+
suppressedByInterference: counts.suppressedByInterference,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
|
|
46
|
+
* `ctx.tenantId` and keeps that order whatever `mode` says; `retrieve` is the
|
|
47
|
+
* mode-aware, strengthening variant the HTTP route uses.
|
|
48
|
+
*
|
|
49
|
+
* **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
|
|
50
|
+
* lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
|
|
51
|
+
* CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
|
|
52
|
+
* are programmatic: they either pass explicit ids to `api.outcome` or call
|
|
53
|
+
* `api.getContext` first for the context-then-outcome workflow (getContext
|
|
54
|
+
* DOES write `last_retrieval_ids`). Adding the side-effect here would change
|
|
55
|
+
* `api.recall` from a pure read into a read+write, breaking SDK callers who
|
|
56
|
+
* batch recall calls in a row. Locked by
|
|
57
|
+
* `tests/api-recall-no-side-effects.test.ts`.
|
|
58
|
+
*/
|
|
59
|
+
export function recall(ctx, opts) {
|
|
60
|
+
// A member key may not unlock a private or quarantined scope by naming it.
|
|
61
|
+
assertScopeRequestAllowed(ctx.actor, opts.scope);
|
|
62
|
+
const windowSize = recallWindowSize(opts);
|
|
63
|
+
return recallFrom(ctx, opts, windowSize, loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false));
|
|
64
|
+
}
|
|
65
|
+
/** Mode-aware recall that strengthens each returned row; never writes last_retrieval_ids (v1.11.5 lock). */
|
|
66
|
+
export async function retrieve(ctx, opts) {
|
|
67
|
+
assertScopeRequestAllowed(ctx.actor, opts.scope);
|
|
68
|
+
const windowSize = recallWindowSize(opts);
|
|
69
|
+
if (opts.showRanked)
|
|
70
|
+
return retrieveFromStore(ctx, opts, windowSize, opts.showRanked);
|
|
71
|
+
let candidates = loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false);
|
|
72
|
+
if (opts.mode === 'hybrid' || opts.mode === 'physics') {
|
|
73
|
+
const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, scope: opts.scope ?? null, vectorCandidates: recallVectorSpec(ctx, opts) };
|
|
74
|
+
const ranked = opts.mode === 'physics'
|
|
75
|
+
? await physicsSearch(opts.query, candidates, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
|
|
76
|
+
: await hybridSearch(opts.query, candidates, searchOpts);
|
|
77
|
+
const rankedIds = new Set(ranked.map((r) => r.entry.id));
|
|
78
|
+
candidates = [...ranked.map((r) => r.entry), ...candidates.filter((e) => !rankedIds.has(e.id))];
|
|
79
|
+
}
|
|
80
|
+
const result = recallFrom(ctx, opts, windowSize, candidates);
|
|
81
|
+
strengthenRetrieved(ctx.hippoRoot, result.results.map((r) => r.id), { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
/** api.retrieve's vector arm: the recall load's exact-scope rule, current rows only. */
|
|
85
|
+
function recallVectorSpec(ctx, opts) {
|
|
86
|
+
return {
|
|
87
|
+
tenantId: ctx.tenantId,
|
|
88
|
+
scope: recallScopeFilter(opts.scope, 'exact'),
|
|
89
|
+
includeSuperseded: false,
|
|
90
|
+
admit: (e) => passesScopeFilterForRecall(e.scope ?? null, opts.scope),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Tag, pin and recency boosts can lift a row from deep in the BM25 order, so MCP ranks a wide lexical window.
|
|
94
|
+
const SHOW_RANKED_LEXICAL_WINDOW = 1000;
|
|
95
|
+
/** `retrieve` under `showRanked`: physics when `mode` says so, hybrid otherwise, over a wide lexical window plus the nearest vectors. */
|
|
96
|
+
async function retrieveFromStore(ctx, opts, windowSize, show) {
|
|
97
|
+
const loaded = loadRecallSearchEntries(ctx.hippoRoot, opts.query, Math.max(windowSize, SHOW_RANKED_LEXICAL_WINDOW), ctx.tenantId, opts.scope, 'exact', false);
|
|
98
|
+
const pool = loaded.filter((e) => passesScopeFilterForRecall(e.scope ?? null, opts.scope));
|
|
99
|
+
// No scope option: the scope boost follows HIPPO_SCOPE and the skill env, as MCP recall always ranked.
|
|
100
|
+
const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, vectorCandidates: recallVectorSpec(ctx, opts) };
|
|
101
|
+
let ranked = opts.mode === 'physics'
|
|
102
|
+
? await physicsSearch(opts.query, pool, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
|
|
103
|
+
: await hybridSearch(opts.query, pool, searchOpts);
|
|
104
|
+
if (opts.sessionId && !opts.goalTag) {
|
|
105
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
106
|
+
try {
|
|
107
|
+
ranked = applyGoalStackBoost(db, ranked, { sessionId: opts.sessionId, tenantId: ctx.tenantId, limit: ranked.length });
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
closeHippoDb(db);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const window = ranked.slice(0, windowSize).map((r) => r.entry);
|
|
114
|
+
const result = recallFrom(ctx, { ...opts, suppressRecallTrace: true }, windowSize, window);
|
|
115
|
+
// Rows the vector arm added count as candidates too.
|
|
116
|
+
const inPool = new Set(pool.map((e) => e.id));
|
|
117
|
+
const candidates = [...pool, ...ranked.map((r) => r.entry).filter((e) => !inPool.has(e.id))];
|
|
118
|
+
const shown = show({ ranked, pool: candidates, droppedByScope: loaded.length - pool.length }, result);
|
|
119
|
+
strengthenRetrieved(ctx.hippoRoot, shown, { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
|
|
120
|
+
if (!opts.suppressRecallTrace) {
|
|
121
|
+
const scores = new Map(ranked.map((r) => [r.entry.id, r.score]));
|
|
122
|
+
writeRecallTraceAtRoot(ctx.hippoRoot, {
|
|
123
|
+
tenantId: ctx.tenantId,
|
|
124
|
+
sessionId: opts.sessionId ?? null,
|
|
125
|
+
pipeline: 'mcp',
|
|
126
|
+
query: opts.query,
|
|
127
|
+
results: shown.map((id) => ({ memoryId: id, score: scores.get(id) ?? 0 })),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
/** Contract preflight: throws before any store-touching work. */
|
|
133
|
+
function recallWindowSize(opts) {
|
|
134
|
+
// F5 (v1.6.5) preflight — codex P1: original guard fired AFTER
|
|
135
|
+
// loadSearchEntries (which runs initStore, migrating legacy state on first
|
|
136
|
+
// call). For a true contract preflight we want the throw before any
|
|
137
|
+
// store-touching work. Single check here; the consumer site at
|
|
138
|
+
// `if (freshTailCount > 0)` does NOT re-validate (would be a no-op).
|
|
139
|
+
const freshTailCountPreflight = opts.freshTailCount ?? 0;
|
|
140
|
+
if (freshTailCountPreflight > 0 &&
|
|
141
|
+
!opts.freshTailSessionId &&
|
|
142
|
+
envRequireSessionScopedFreshTail()) {
|
|
143
|
+
throw new RecallContractError('fresh_tail_requires_session_id', 'fresh-tail requires a session id when HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1; ' +
|
|
144
|
+
'pass opts.freshTailSessionId or unset the env to allow tenant-wide fresh-tail.');
|
|
145
|
+
}
|
|
146
|
+
// F3 (v1.7.0): scorerWindow opt-in. When undefined (default),
|
|
147
|
+
// loadSearchEntries uses its own store-internal default — this
|
|
148
|
+
// preserves every pre-v1.7.0 caller's behaviour bit-for-bit (codex
|
|
149
|
+
// mk2-pass P0-1: defaulting to `limit` would have shrunk the
|
|
150
|
+
// candidate pool and killed overflow summaries).
|
|
151
|
+
// DEFAULT_SEARCH_CANDIDATE_LIMIT is imported from store.ts so the two
|
|
152
|
+
// values cannot drift (codex diff-pass P1 #3).
|
|
153
|
+
// Validate the input — codex diff-pass P1 #1 caught that scorerWindow=0
|
|
154
|
+
// would route through FTS/LIKE LIMIT 0 and then fall through to an
|
|
155
|
+
// uncapped full-store fallback. Reject non-positive / non-finite values.
|
|
156
|
+
if (opts.scorerWindow !== undefined) {
|
|
157
|
+
if (!Number.isFinite(opts.scorerWindow) ||
|
|
158
|
+
!Number.isInteger(opts.scorerWindow) ||
|
|
159
|
+
opts.scorerWindow < 1) {
|
|
160
|
+
throw new RecallContractError('invalid_scorer_window', `scorerWindow must be a positive integer; got ${opts.scorerWindow}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return opts.scorerWindow ?? DEFAULT_SEARCH_CANDIDATE_LIMIT;
|
|
164
|
+
}
|
|
165
|
+
function recallFrom(ctx, opts, windowSize, all) {
|
|
166
|
+
const limit = opts.limit ?? 10;
|
|
167
|
+
const window = admitCandidates(opts, all, limit);
|
|
168
|
+
// One db handle spans the goal-stack boost and the audit and trace rows; it closes before the continuity block.
|
|
169
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
170
|
+
let bands;
|
|
171
|
+
try {
|
|
172
|
+
bands = rankBands(db, ctx, opts, window, limit);
|
|
173
|
+
auditAndTraceRecall(db, ctx, opts, bands.rankedOut);
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
closeHippoDb(db);
|
|
177
|
+
}
|
|
178
|
+
const rankedOut = bands.rankedOut;
|
|
179
|
+
const { continuity, continuityTokens } = opts.includeContinuity
|
|
180
|
+
? loadContinuity(ctx, opts)
|
|
181
|
+
: { continuity: undefined, continuityTokens: undefined };
|
|
182
|
+
// Query-derived, so MCP and CLI read this one hint instead of recomputing; HIPPO_AUTODEBIAS=off disables it.
|
|
183
|
+
// The hint and the no-class-match / tiebreak watching variant are mutually exclusive; both go out as optional fields.
|
|
184
|
+
const planningFallacyOutput = computePlanningFallacyOutput(ctx.hippoRoot, ctx.tenantId, opts.query, { actor: ctx.actor.subject });
|
|
185
|
+
const planningFallacyHint = planningFallacyOutput.hint ?? null;
|
|
186
|
+
const planningFallacyWatching = planningFallacyOutput.watching ?? null;
|
|
187
|
+
const { anchoringHint, suppressedByInterference } = detectRecallAnchoring(ctx, opts, rankedOut[0]?.id ?? null);
|
|
188
|
+
const availabilityHint = detectRecallAvailability(ctx, opts, bands.baseSlice, window.entries);
|
|
189
|
+
const result = {
|
|
190
|
+
results: rankedOut,
|
|
191
|
+
total: window.entries.length,
|
|
192
|
+
tokens: rankedOut.reduce((acc, r) => acc + estimateTokens(r.content), 0),
|
|
193
|
+
continuity,
|
|
194
|
+
continuityTokens,
|
|
195
|
+
windowSize,
|
|
196
|
+
suppressionSummary: buildSuppressionSummary({
|
|
197
|
+
totalCandidates: all.length,
|
|
198
|
+
droppedPreRank: window.droppedPreRank + bands.heldDropped,
|
|
199
|
+
droppedByBudget: window.droppedByBudget,
|
|
200
|
+
summarySubstitutionsAdded: bands.summarySubstitutions,
|
|
201
|
+
freshTailAdded: bands.freshTailAdded,
|
|
202
|
+
suppressedByInterference,
|
|
203
|
+
}),
|
|
204
|
+
};
|
|
205
|
+
if (planningFallacyHint)
|
|
206
|
+
result.planningFallacyHint = planningFallacyHint;
|
|
207
|
+
if (planningFallacyWatching)
|
|
208
|
+
result.planningFallacyWatching = planningFallacyWatching;
|
|
209
|
+
if (anchoringHint)
|
|
210
|
+
result.anchoringHint = anchoringHint;
|
|
211
|
+
if (availabilityHint)
|
|
212
|
+
result.availabilityHint = availabilityHint;
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
// The SQL load already applied tenant and scope; any recall-mode loader must go through loadRecallSearchEntries.
|
|
216
|
+
function admitCandidates(opts, all, limit) {
|
|
217
|
+
const current = all.filter((e) => !e.superseded_by);
|
|
218
|
+
let entries;
|
|
219
|
+
if (opts.scope !== undefined && opts.scope !== '') {
|
|
220
|
+
// SQL already exact-matched; the JS filter is defense-in-depth against a SQL-clause regression.
|
|
221
|
+
entries = current.filter((e) => e.scope === opts.scope);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// SQL pre-filtered ':private:' loosely before the window; this is the exact anchored `<source>:private:*` rule.
|
|
225
|
+
entries = current.filter((e) => !isRestrictedScope(e.scope ?? null));
|
|
226
|
+
}
|
|
227
|
+
const droppedPreRank = all.length - entries.length;
|
|
228
|
+
entries = entries
|
|
229
|
+
.map((e, i) => ({ e, s: (1 - i / entries.length) * churnStaleFactor(e) }))
|
|
230
|
+
.sort((a, b) => b.s - a.s)
|
|
231
|
+
.map((r) => r.e);
|
|
232
|
+
// BM25 ordering already comes from loadRecallSearchEntries; cap to `limit`.
|
|
233
|
+
const baseSlice = entries.slice(0, limit);
|
|
234
|
+
return { entries, baseSlice, droppedPreRank, droppedByBudget: entries.length - baseSlice.length };
|
|
235
|
+
}
|
|
236
|
+
// The goal-stack boost touches the primary band only; the fresh-tail and summary bands keep their fixed placement.
|
|
237
|
+
function rankBands(db, ctx, opts, window, limit) {
|
|
238
|
+
let baseScored = window.baseSlice.map((entry, idx) => ({
|
|
239
|
+
entry,
|
|
240
|
+
score: Math.max(0, 1 - idx / Math.max(1, limit)),
|
|
241
|
+
}));
|
|
242
|
+
// Allocated only under explain, so the boost's default-path math stays byte-identical.
|
|
243
|
+
const explainTrace = opts.explain ? new Map() : undefined;
|
|
244
|
+
if (opts.sessionId && !opts.goalTag) {
|
|
245
|
+
baseScored = applyGoalStackBoost(db, baseScored, {
|
|
246
|
+
sessionId: opts.sessionId,
|
|
247
|
+
tenantId: ctx.tenantId,
|
|
248
|
+
limit,
|
|
249
|
+
trace: explainTrace,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
let substituted = (opts.summarizeOverflow ?? true) && window.entries.length > limit
|
|
253
|
+
? substituteOverflow(ctx, opts, window.entries, baseScored.map((r) => r.entry), limit)
|
|
254
|
+
: [];
|
|
255
|
+
let heldDropped = 0;
|
|
256
|
+
if (!opts.keepHeldCopies) {
|
|
257
|
+
const shownIds = new Set(dropHeldCopies([...baseScored.map((r) => r.entry), ...substituted.map((s) => s.entry)], (e) => e).map((e) => e.id));
|
|
258
|
+
heldDropped = baseScored.filter((r) => !shownIds.has(r.entry.id)).length;
|
|
259
|
+
baseScored = baseScored.filter((r) => shownIds.has(r.entry.id));
|
|
260
|
+
substituted = substituted.filter((s) => shownIds.has(s.entry.id));
|
|
261
|
+
}
|
|
262
|
+
const baseSlice = baseScored.map((r) => r.entry);
|
|
263
|
+
const baseRanked = baseScored.map((r) => baseItem(r, opts, explainTrace));
|
|
264
|
+
const summaryRanked = substituted.map((s) => summaryItem(s, opts));
|
|
265
|
+
const freshRanked = (opts.freshTailCount ?? 0) > 0
|
|
266
|
+
? freshTailBand(ctx, opts, baseRanked, summaryRanked, opts.keepHeldCopies ? [] : [...baseSlice, ...substituted.map((s) => s.entry)])
|
|
267
|
+
: [];
|
|
268
|
+
return {
|
|
269
|
+
rankedOut: [...freshRanked, ...baseRanked, ...summaryRanked],
|
|
270
|
+
baseSlice,
|
|
271
|
+
heldDropped,
|
|
272
|
+
summarySubstitutions: substituted.length,
|
|
273
|
+
freshTailAdded: freshRanked.length,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// When the overflow holds 2+ children of one level-2 summary, that summary stands in for them, capped at 30% of
|
|
277
|
+
// `limit`. Each one is tenant-scoped and re-checked against the scope filter; drillDown recovers the children.
|
|
278
|
+
function substituteOverflow(ctx, opts, entries, baseSlice, limit) {
|
|
279
|
+
const overflow = entries.slice(limit);
|
|
280
|
+
const baseIds = new Set(baseSlice.map((e) => e.id));
|
|
281
|
+
const overflowByParent = new Map();
|
|
282
|
+
for (const e of overflow) {
|
|
283
|
+
const parentId = e.dag_parent_id;
|
|
284
|
+
if (!parentId)
|
|
285
|
+
continue;
|
|
286
|
+
if ((e.dag_level ?? 0) > 1)
|
|
287
|
+
continue;
|
|
288
|
+
const list = overflowByParent.get(parentId) ?? [];
|
|
289
|
+
list.push(e);
|
|
290
|
+
overflowByParent.set(parentId, list);
|
|
291
|
+
}
|
|
292
|
+
const eligibleParentIds = Array.from(overflowByParent.keys()).filter((pid) => (overflowByParent.get(pid)?.length ?? 0) >= 2 && !baseIds.has(pid));
|
|
293
|
+
if (eligibleParentIds.length === 0)
|
|
294
|
+
return [];
|
|
295
|
+
const parents = loadEntriesByIds(ctx.hippoRoot, eligibleParentIds, ctx.tenantId);
|
|
296
|
+
const eligibleParents = parents.filter((p) => (p.dag_level ?? 0) === 2 && !p.superseded_by && passesScopeFilterForRecall(p.scope ?? null, opts.scope));
|
|
297
|
+
const maxSub = Math.max(1, Math.ceil(limit * 0.3));
|
|
298
|
+
// Most overflowed children first; compareEntryIdentity only breaks a tie, which used to fall to scan order.
|
|
299
|
+
eligibleParents.sort((a, b) => {
|
|
300
|
+
const ac = overflowByParent.get(a.id)?.length ?? 0;
|
|
301
|
+
const bc = overflowByParent.get(b.id)?.length ?? 0;
|
|
302
|
+
return bc !== ac ? bc - ac : compareEntryIdentity(a, b);
|
|
303
|
+
});
|
|
304
|
+
return eligibleParents.slice(0, maxSub).map((p) => ({
|
|
305
|
+
entry: p,
|
|
306
|
+
childIds: (overflowByParent.get(p.id) ?? []).map((e) => e.id),
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
function baseItem(r, opts, explainTrace) {
|
|
310
|
+
const item = {
|
|
311
|
+
id: r.entry.id,
|
|
312
|
+
content: r.entry.content,
|
|
313
|
+
score: r.score,
|
|
314
|
+
layer: r.entry.layer,
|
|
315
|
+
strength: r.entry.strength,
|
|
316
|
+
};
|
|
317
|
+
// Only this band passes through the goal boost, so only it can carry a rerank step.
|
|
318
|
+
if (opts.explain) {
|
|
319
|
+
item.rerankPipeline = 'api';
|
|
320
|
+
const step = explainTrace?.get(r.entry.id);
|
|
321
|
+
if (step)
|
|
322
|
+
item.rerankTrace = [step];
|
|
323
|
+
}
|
|
324
|
+
return item;
|
|
325
|
+
}
|
|
326
|
+
// Score 0.5 keeps a summary below the strong top-N matches but above the weakest leaves.
|
|
327
|
+
function summaryItem(s, opts) {
|
|
328
|
+
const item = {
|
|
329
|
+
id: s.entry.id,
|
|
330
|
+
content: s.entry.content,
|
|
331
|
+
score: 0.5,
|
|
332
|
+
layer: s.entry.layer,
|
|
333
|
+
strength: s.entry.strength,
|
|
334
|
+
isSummary: true,
|
|
335
|
+
substitutedFor: s.childIds,
|
|
336
|
+
descendantCount: s.entry.descendant_count ?? s.childIds.length,
|
|
337
|
+
};
|
|
338
|
+
if (opts.explain)
|
|
339
|
+
item.rerankPipeline = 'api';
|
|
340
|
+
return item;
|
|
341
|
+
}
|
|
342
|
+
// The last N raw rows, so "what did I just see" always covers the recent window. A recent row already in the BM25
|
|
343
|
+
// band is only tagged isFreshTail; new ones are prepended, so every recent row appears exactly once.
|
|
344
|
+
function freshTailBand(ctx, opts, baseRanked, summaryRanked, shownEntries) {
|
|
345
|
+
// The session-id contract was already checked by recallWindowSize's preflight.
|
|
346
|
+
const recent = loadFreshRawMemories(ctx.hippoRoot, opts.freshTailCount ?? 0, ctx.tenantId, opts.freshTailSessionId);
|
|
347
|
+
const recentScoped = recent.filter((m) => passesScopeFilterForRecall(m.scope ?? null, opts.scope));
|
|
348
|
+
const recentIdSet = new Set(recentScoped.map((m) => m.id));
|
|
349
|
+
for (const r of baseRanked) {
|
|
350
|
+
if (recentIdSet.has(r.id))
|
|
351
|
+
r.isFreshTail = true;
|
|
352
|
+
}
|
|
353
|
+
const seenIds = new Set([...baseRanked.map((r) => r.id), ...summaryRanked.map((r) => r.id)]);
|
|
354
|
+
const shownKeys = storedTextKeys(shownEntries);
|
|
355
|
+
const freshRanked = [];
|
|
356
|
+
for (const m of recentScoped) {
|
|
357
|
+
if (seenIds.has(m.id) || shownKeys.has(duplicateKey(m.content)))
|
|
358
|
+
continue;
|
|
359
|
+
shownKeys.add(duplicateKey(m.content));
|
|
360
|
+
const item = {
|
|
361
|
+
id: m.id,
|
|
362
|
+
content: m.content,
|
|
363
|
+
score: 1.0,
|
|
364
|
+
layer: m.layer,
|
|
365
|
+
strength: m.strength,
|
|
366
|
+
isFreshTail: true,
|
|
367
|
+
};
|
|
368
|
+
if (opts.explain)
|
|
369
|
+
item.rerankPipeline = 'api';
|
|
370
|
+
freshRanked.push(item);
|
|
371
|
+
seenIds.add(m.id);
|
|
372
|
+
}
|
|
373
|
+
return freshRanked;
|
|
374
|
+
}
|
|
375
|
+
// The audit row stores a hash of the query, never its text, so an archived memory's words cannot persist there.
|
|
376
|
+
// The trace sits beside it as observability, not retrieval state; a caller that traces its own result set suppresses it.
|
|
377
|
+
function auditAndTraceRecall(db, ctx, opts, rankedOut) {
|
|
378
|
+
appendAuditEvent(db, {
|
|
379
|
+
tenantId: ctx.tenantId,
|
|
380
|
+
actor: ctx.actor.subject,
|
|
381
|
+
op: 'recall',
|
|
382
|
+
metadata: {
|
|
383
|
+
...auditQueryFields(opts.query),
|
|
384
|
+
results: rankedOut.length,
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
if (!opts.suppressRecallTrace) {
|
|
388
|
+
writeRecallTrace(db, {
|
|
389
|
+
tenantId: ctx.tenantId,
|
|
390
|
+
sessionId: opts.sessionId ?? null,
|
|
391
|
+
pipeline: 'api',
|
|
392
|
+
query: opts.query,
|
|
393
|
+
explainMode: opts.explain === true,
|
|
394
|
+
results: rankedOut.map((r) => ({
|
|
395
|
+
memoryId: r.id,
|
|
396
|
+
score: r.score,
|
|
397
|
+
rerankSteps: r.rerankTrace,
|
|
398
|
+
})),
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// No active snapshot means no anchor, so no handoff or events: a stale handoff from a closed session never resurfaces.
|
|
403
|
+
function loadContinuity(ctx, opts) {
|
|
404
|
+
const snapshot = loadActiveTaskSnapshot(ctx.hippoRoot, ctx.tenantId);
|
|
405
|
+
const sessionId = snapshot?.session_id ?? undefined;
|
|
406
|
+
const sessionHandoff = sessionId
|
|
407
|
+
? loadLatestHandoff(ctx.hippoRoot, ctx.tenantId, sessionId)
|
|
408
|
+
: null;
|
|
409
|
+
const recentSessionEvents = sessionId
|
|
410
|
+
? listSessionEvents(ctx.hippoRoot, ctx.tenantId, { session_id: sessionId, limit: 5 })
|
|
411
|
+
: [];
|
|
412
|
+
// The memory-recall scope rule: an explicit scope must match exactly; without one, private and legacy rows are denied.
|
|
413
|
+
const rowScope = (r) => r?.scope ?? null;
|
|
414
|
+
const filteredSnapshot = snapshot && passesScopeFilterForRecall(rowScope(snapshot), opts.scope) ? snapshot : null;
|
|
415
|
+
const filteredHandoff = sessionHandoff && passesScopeFilterForRecall(rowScope(sessionHandoff), opts.scope) ? sessionHandoff : null;
|
|
416
|
+
const filteredEvents = recentSessionEvents.filter((e) => passesScopeFilterForRecall(rowScope(e), opts.scope));
|
|
417
|
+
const continuity = {
|
|
418
|
+
activeSnapshot: filteredSnapshot,
|
|
419
|
+
sessionHandoff: filteredHandoff,
|
|
420
|
+
recentSessionEvents: filteredEvents,
|
|
421
|
+
};
|
|
422
|
+
return { continuity, continuityTokens: continuityTokensOf(continuity) };
|
|
423
|
+
}
|
|
424
|
+
function continuityTokensOf(c) {
|
|
425
|
+
const filteredSnapshot = c.activeSnapshot;
|
|
426
|
+
const filteredHandoff = c.sessionHandoff;
|
|
427
|
+
const tokenize = (s) => s ? estimateTokens(s) : 0;
|
|
428
|
+
return tokenize(filteredSnapshot?.task) +
|
|
429
|
+
tokenize(filteredSnapshot?.summary) +
|
|
430
|
+
tokenize(filteredSnapshot?.next_step) +
|
|
431
|
+
tokenize(filteredHandoff?.summary) +
|
|
432
|
+
tokenize(filteredHandoff?.nextAction) +
|
|
433
|
+
(filteredHandoff?.artifacts ?? []).reduce((acc, a) => acc + tokenize(a), 0) +
|
|
434
|
+
(filteredHandoff?.constraints ?? []).reduce((acc, c) => acc + tokenize(c), 0) +
|
|
435
|
+
tokenize(filteredHandoff?.evidence ? formatHandoffEvidenceLine(filteredHandoff.evidence) : null) +
|
|
436
|
+
tokenize(filteredHandoff?.outcome) +
|
|
437
|
+
tokenize(filteredHandoff?.targetRuntime) +
|
|
438
|
+
tokenize(filteredHandoff?.cardId) +
|
|
439
|
+
c.recentSessionEvents.reduce((acc, e) => acc + tokenize(e.content), 0);
|
|
440
|
+
}
|
|
441
|
+
/** One audit row on its own short-lived handle, as each bias detector writes it. */
|
|
442
|
+
function appendRecallAudit(ctx, event) {
|
|
443
|
+
const db = openHippoDb(ctx.hippoRoot);
|
|
444
|
+
try {
|
|
445
|
+
appendAuditEvent(db, { tenantId: ctx.tenantId, actor: ctx.actor.subject, ...event });
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
closeHippoDb(db);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// A pure read of the caller's recallHistory snapshot against this top-1. HIPPO_ANCHORING=off skips even the detect
|
|
452
|
+
// call; CLI paths pass no history (cmdRecall computes its own hint), so the hint stays absent there.
|
|
453
|
+
function detectRecallAnchoring(ctx, opts, topMemoryId) {
|
|
454
|
+
if (!biasHintEnabled('anchoring') || !opts.recallHistory)
|
|
455
|
+
return { anchoringHint: null, suppressedByInterference: 0 };
|
|
456
|
+
const queryHash = hashQueryText(opts.query);
|
|
457
|
+
const anchoringHint = detectAnchoring(opts.recallHistory, queryHash, topMemoryId);
|
|
458
|
+
if (anchoringHint?.reason === 'memory_dominance') {
|
|
459
|
+
appendRecallAudit(ctx, {
|
|
460
|
+
op: 'recall_anchor_detected_memory_dominance',
|
|
461
|
+
targetId: anchoringHint.memoryId,
|
|
462
|
+
metadata: {
|
|
463
|
+
memory_id: anchoringHint.memoryId,
|
|
464
|
+
query_count: anchoringHint.queryCount ?? null,
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
return { anchoringHint, suppressedByInterference: 1 };
|
|
468
|
+
}
|
|
469
|
+
if (anchoringHint?.reason === 'query_repeat') {
|
|
470
|
+
appendRecallAudit(ctx, {
|
|
471
|
+
op: 'recall_anchor_detected_query_repeat',
|
|
472
|
+
targetId: anchoringHint.memoryId,
|
|
473
|
+
metadata: { memory_id: anchoringHint.memoryId },
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
return { anchoringHint, suppressedByInterference: 0 };
|
|
477
|
+
}
|
|
478
|
+
// Compares the returned top-K's ages with the scope-filtered pool it came from, never `all`, whose hidden rows would
|
|
479
|
+
// leak pool shape. A soft warning only; HIPPO_AVAILABILITY=off or a caller computing its own hint skips it.
|
|
480
|
+
function detectRecallAvailability(ctx, opts, baseSlice, entries) {
|
|
481
|
+
if (!biasHintEnabled('availability') || opts.suppressAvailabilityHint)
|
|
482
|
+
return null;
|
|
483
|
+
const availabilityHint = detectAvailabilityBias({
|
|
484
|
+
topK: baseSlice.map((e) => ({ id: e.id, created: e.created })),
|
|
485
|
+
pool: entries.map((e) => ({ id: e.id, created: e.created })),
|
|
486
|
+
});
|
|
487
|
+
if (availabilityHint) {
|
|
488
|
+
appendRecallAudit(ctx, {
|
|
489
|
+
op: 'recall_availability_detected',
|
|
490
|
+
metadata: {
|
|
491
|
+
recent_fraction: availabilityHint.recentFraction,
|
|
492
|
+
older_passed_over: availabilityHint.olderCandidatesPassedOver,
|
|
493
|
+
returned_count: availabilityHint.returnedCount,
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return availabilityHint;
|
|
498
|
+
}
|
|
499
|
+
//# sourceMappingURL=recall.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { DatabaseSyncLike } from '../db.js';
|
|
2
|
+
import { type MemoryKind } from '../memory.js';
|
|
3
|
+
import type { Context } from './types.js';
|
|
4
|
+
export interface RememberOpts {
|
|
5
|
+
content: string;
|
|
6
|
+
kind?: MemoryKind;
|
|
7
|
+
scope?: string;
|
|
8
|
+
owner?: string;
|
|
9
|
+
artifactRef?: string;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Optional hook invoked inside the same transaction as the underlying
|
|
13
|
+
* memories INSERT. Used by ingestion connectors (E1.3+) to stamp
|
|
14
|
+
* idempotency / cursor rows atomically with the memory row, so a crash
|
|
15
|
+
* mid-write cannot produce a memory without its corresponding side-effect
|
|
16
|
+
* log row (or vice versa). If the callback throws, the INSERT is rolled
|
|
17
|
+
* back and the error is rethrown.
|
|
18
|
+
*/
|
|
19
|
+
afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
|
|
20
|
+
/** CD5: connector-ingested content an agent doesn't control; gates detectInstruction. CLI/HTTP/MCP never set this. */
|
|
21
|
+
untrusted?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface RememberResult {
|
|
24
|
+
id: string;
|
|
25
|
+
kind: MemoryKind;
|
|
26
|
+
tenantId: string;
|
|
27
|
+
/** Set only when untrusted content was flagged and quarantined instead of stored under its requested scope. */
|
|
28
|
+
quarantined?: {
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
/** Set only when the content held secret material: untrusted text had it redacted, typed text was stored as sent. */
|
|
32
|
+
warnings?: string[];
|
|
33
|
+
}
|
|
34
|
+
export declare function remember(ctx: Context, opts: RememberOpts): RememberResult;
|
|
35
|
+
//# sourceMappingURL=remember.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Write path: remember stores one memory after secret vetting and, for untrusted content, the instruction check.
|
|
2
|
+
import { writeEntry } from '../store/entry-writes.js';
|
|
3
|
+
import { detectInstruction } from '../instruction-detect.js';
|
|
4
|
+
import { quarantineScopeFor, recordQuarantine } from '../quarantine.js';
|
|
5
|
+
import { createMemory } from '../memory.js';
|
|
6
|
+
import { loadConfig } from '../config.js';
|
|
7
|
+
import { vetSecrets } from '../secret-detect.js';
|
|
8
|
+
export function remember(ctx, opts) {
|
|
9
|
+
const vetted = vetSecrets(opts.content, opts.tags ?? [], opts.untrusted === true);
|
|
10
|
+
const detection = opts.untrusted ? detectInstruction(vetted.content) : { flagged: false, reason: null };
|
|
11
|
+
const requestedScope = opts.scope ?? null;
|
|
12
|
+
const entry = createMemory(vetted.content, {
|
|
13
|
+
kind: opts.kind ?? 'distilled',
|
|
14
|
+
scope: detection.flagged ? quarantineScopeFor(requestedScope) : requestedScope,
|
|
15
|
+
owner: opts.owner ?? null,
|
|
16
|
+
artifact_ref: opts.artifactRef ?? null,
|
|
17
|
+
tags: opts.tags,
|
|
18
|
+
tenantId: ctx.tenantId,
|
|
19
|
+
baseHalfLifeDays: loadConfig(ctx.hippoRoot).defaultHalfLifeDays,
|
|
20
|
+
});
|
|
21
|
+
// writeEntry threads ctx.actor.subject into its internal audit hook, so exactly
|
|
22
|
+
// one 'remember' event lands in the log with the supplied actor.
|
|
23
|
+
const afterWrite = detection.flagged
|
|
24
|
+
? (db, memoryId) => {
|
|
25
|
+
recordQuarantine(db, {
|
|
26
|
+
tenantId: ctx.tenantId,
|
|
27
|
+
memoryId,
|
|
28
|
+
originalScope: requestedScope,
|
|
29
|
+
reason: detection.reason ?? 'unknown',
|
|
30
|
+
actor: ctx.actor.subject,
|
|
31
|
+
});
|
|
32
|
+
opts.afterWrite?.(db, memoryId);
|
|
33
|
+
}
|
|
34
|
+
: opts.afterWrite;
|
|
35
|
+
writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor.subject, afterWrite });
|
|
36
|
+
const result = { id: entry.id, kind: entry.kind, tenantId: ctx.tenantId };
|
|
37
|
+
if (detection.flagged)
|
|
38
|
+
result.quarantined = { reason: detection.reason ?? 'unknown' };
|
|
39
|
+
if (vetted.warnings.length > 0)
|
|
40
|
+
result.warnings = vetted.warnings;
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=remember.js.map
|