hippo-memory 1.71.0 → 2.0.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 +7 -5
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +11 -26
- 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 +3 -2
- package/dist/api/audit.d.ts +30 -2
- package/dist/api/audit.js +48 -7
- package/dist/api/auth.d.ts +11 -9
- package/dist/api/auth.js +39 -40
- 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-auto.js +4 -2
- package/dist/api/context-render.js +4 -3
- package/dist/api/context-select.js +15 -29
- package/dist/api/context.js +29 -18
- 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 +3 -2
- 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 +7 -3
- package/dist/api/forget.js +24 -14
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.js +2 -1
- 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 +5 -1
- package/dist/api/learn.js +71 -44
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +21 -1
- package/dist/api/memories.js +51 -1
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/objects.js +2 -1
- package/dist/api/outcome.d.ts +5 -5
- package/dist/api/outcome.js +17 -16
- 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 +8 -1
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +3 -3
- package/dist/api/promote.js +26 -28
- package/dist/api/prompt-hook.d.ts +17 -2
- package/dist/api/prompt-hook.js +45 -4
- package/dist/api/quarantine.js +2 -1
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +10 -5
- package/dist/api/recall-pipeline.js +23 -24
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +3 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +51 -73
- package/dist/api/remember-local.d.ts +5 -2
- package/dist/api/remember-local.js +15 -7
- package/dist/api/remember.d.ts +7 -3
- package/dist/api/remember.js +19 -16
- package/dist/api/session-end.d.ts +46 -0
- package/dist/api/session-end.js +131 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +16 -11
- package/dist/api/sleep.js +4 -3
- 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 +2 -2
- package/dist/api/types.d.ts +3 -7
- 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 +7 -7
- package/dist/capture/compaction-spool.js +60 -51
- 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 +3 -2
- package/dist/capture/session-worker.js +22 -10
- 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 +20 -20
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +16 -17
- 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 +6 -2
- package/dist/cli/client.js +37 -21
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +13 -13
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +2 -2
- package/dist/cli/curate.js +32 -36
- 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 +7 -285
- 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 +6 -6
- package/dist/cli/hook-runtime.js +9 -36
- 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/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/object-verbs.d.ts +2 -2
- package/dist/cli/object-verbs.js +4 -4
- 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 +174 -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 +18 -17
- package/dist/cli/remember.js +17 -17
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +11 -6
- package/dist/cli/session-hooks.d.ts +1 -5
- package/dist/cli/session-hooks.js +89 -168
- 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 +3 -3
- package/dist/cli/transfer.js +64 -43
- package/dist/cli/usage.d.ts +1 -80
- package/dist/cli/usage.js +2 -696
- package/dist/cli/verb-row.d.ts +34 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +234 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +236 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +257 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +314 -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 +24 -315
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +39 -4
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/deletion.js +2 -1
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +5 -29
- package/dist/connectors/github/tenant-routing.js +2 -1
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +35 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +29 -0
- package/dist/connectors/slack/deletion.js +2 -1
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +4 -28
- package/dist/connectors/slack/tenant-routing.js +2 -1
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +2 -2
- package/dist/consolidate/dag.js +29 -18
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +6 -4
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +3 -2
- package/dist/consolidate/merge.js +8 -8
- 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 +9 -6
- package/dist/consolidate/traces.js +5 -5
- 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 +22 -18
- 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 +4 -4
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +14 -8
- package/dist/core/memory.js +35 -23
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.d.ts +3 -1
- package/dist/core/physics.js +23 -18
- 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 +12 -2
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/core/search-types.d.ts +1 -1
- package/dist/dashboard/dashboard-actions.d.ts +2 -2
- package/dist/dashboard/dashboard-actions.js +5 -5
- package/dist/dashboard/dashboard-queries.js +2 -7
- package/dist/dashboard/dashboard-snapshot.js +1 -3
- package/dist/dashboard/dashboard.js +16 -5
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +2 -2
- package/dist/db/connect.js +7 -7
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +14 -7
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/v11.js +1 -0
- package/dist/db/migrations/v14.js +1 -0
- 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.d.ts +0 -4
- package/dist/db/physics-state.js +7 -33
- package/dist/db/request-stores.d.ts +1 -0
- package/dist/db/request-stores.js +2 -1
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +19 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +18 -15
- 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 +19 -25
- 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/entry/store-kit.d.ts +37 -0
- package/dist/entry/store-kit.js +25 -0
- package/dist/entry/testing.d.ts +6 -0
- package/dist/entry/testing.js +7 -0
- package/dist/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +12 -5
- 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 +10 -4
- 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 +4 -4
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.d.ts +1 -1
- package/dist/importers/vault.js +25 -23
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/learn/autolearn.d.ts +15 -3
- package/dist/learn/autolearn.js +38 -16
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +7 -5
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.d.ts +2 -1
- package/dist/learn/invalidation.js +18 -9
- 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.d.ts +1 -1
- package/dist/mcp/memory-tools.js +8 -9
- 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 +22 -20
- package/dist/mcp/stdio.js +37 -16
- 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 +71 -98
- 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 +12 -0
- package/dist/search/embed-memories.js +389 -0
- package/dist/search/engine.d.ts +8 -0
- package/dist/search/engine.js +10 -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 +14 -17
- package/dist/server/auth.d.ts +3 -1
- package/dist/server/auth.js +24 -15
- package/dist/server/boot.d.ts +2 -1
- package/dist/server/boot.js +34 -84
- package/dist/server/client-ip.d.ts +9 -6
- package/dist/server/client-ip.js +36 -17
- 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 -133
- 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 +19 -40
- 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/tls.d.ts +7 -2
- package/dist/server/tls.js +17 -5
- package/dist/server/types.d.ts +29 -12
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +4 -40
- package/dist/server.js +3 -29
- package/dist/sharing/global-store.d.ts +4 -5
- package/dist/sharing/global-store.js +8 -13
- 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 +10 -3
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +39 -38
- package/dist/store/ambient.js +7 -7
- 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 +59 -30
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +6 -5
- 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 +418 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +7 -1
- package/dist/store/conflicts.js +13 -9
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +33 -0
- package/dist/store/connectors/event-log.d.ts +13 -0
- package/dist/store/connectors/event-log.js +24 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +35 -60
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +24 -57
- package/dist/store/dashboard-reads.js +8 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +40 -6
- package/dist/store/delivery-recorder.d.ts +12 -5
- package/dist/store/delivery-recorder.js +13 -11
- package/dist/store/descendant-page.js +8 -4
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +10 -4
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +35 -4
- package/dist/store/entry-reads.js +86 -19
- package/dist/store/entry-row.js +9 -2
- package/dist/store/entry-writes.d.ts +15 -12
- package/dist/store/entry-writes.js +54 -22
- 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 +22 -19
- package/dist/store/graph-reads.js +9 -6
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/half-life.js +2 -2
- package/dist/store/handoffs.d.ts +10 -4
- package/dist/store/handoffs.js +10 -9
- package/dist/store/index-and-stats.js +2 -2
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +1 -1
- 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 +19 -10
- package/dist/store/open.d.ts +2 -5
- package/dist/store/open.js +42 -54
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +68 -6
- 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/quality-repair.js +1 -1
- package/dist/store/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +20 -3
- package/dist/store/rejected-values.js +16 -10
- 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/rows.js +2 -2
- package/dist/store/rule-sql.d.ts +11 -0
- package/dist/store/rule-sql.js +31 -6
- package/dist/store/search-rows.d.ts +5 -5
- package/dist/store/search-rows.js +18 -16
- 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 +6 -4
- package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
- package/dist/store/sqlite/entry-writes-group.js +3 -3
- 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 +11 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/last-recall-group.d.ts +13 -0
- package/dist/store/sqlite/last-recall-group.js +57 -0
- package/dist/store/sqlite/local.d.ts +0 -17
- package/dist/store/sqlite/local.js +0 -31
- package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
- package/dist/store/sqlite/maintenance-groups.js +60 -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 +15 -7
- package/dist/store/sqlite/store.d.ts +1 -8
- package/dist/store/sqlite/store.js +13 -22
- package/dist/store/summaries.d.ts +10 -3
- package/dist/store/summaries.js +54 -11
- package/dist/store/token-ledger-rows.js +3 -2
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +8 -4
- 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 +6 -1
- package/dist/util/anthropic-messages.js +26 -7
- package/dist/util/atomic-write.d.ts +5 -2
- package/dist/util/atomic-write.js +12 -8
- 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 +12 -2
- package/dist/util/env.js +12 -2
- package/dist/util/format.d.ts +5 -0
- package/dist/util/format.js +10 -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 +9 -3
- package/dist/util/request-scope.js +18 -9
- package/dist/util/secret-detect.js +6 -1
- package/dist/util/spawn-argv.d.ts +9 -0
- package/dist/util/spawn-argv.js +57 -0
- package/dist/util/sql.d.ts +3 -0
- package/dist/util/sql.js +6 -0
- 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/vector-codec.d.ts +4 -0
- package/dist/util/vector-codec.js +15 -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 +4 -2
- package/dist/api/on-store.d.ts +0 -16
- package/dist/api/on-store.js +0 -38
- 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
|
@@ -3,10 +3,6 @@ import { type DatabaseSyncLike } from '../db/index.js';
|
|
|
3
3
|
export declare const TENANT_IS = "+tenant_id = ?";
|
|
4
4
|
/** Read a memory entry by ID. With `tenantId` the read is tenant-scoped (cross-tenant returns null); omitted, no tenant filter is applied. */
|
|
5
5
|
export declare function readEntry(hippoRoot: string, id: string, tenantId?: string): MemoryEntry | null;
|
|
6
|
-
/** Ids per `IN (...)` list: far under SQLite's bound-parameter limit, with room for the tenant filter. */
|
|
7
|
-
export declare const ID_CHUNK = 500;
|
|
8
|
-
/** `items` in consecutive slices of at most `size`. */
|
|
9
|
-
export declare function chunked<T>(items: readonly T[], size?: number): T[][];
|
|
10
6
|
/** Answers whether a tenant's rows in this store hold an id: `ids` are looked up now, one query per chunk, and any other id on its first ask. */
|
|
11
7
|
export declare function heldIdLookup(hippoRoot: string, tenantId: string, ids: readonly string[]): (id: string) => boolean;
|
|
12
8
|
/** Rows by id on the caller's handle, one query per chunk; an id missing or in another tenant is absent from the map. */
|
|
@@ -28,6 +24,19 @@ export declare function loadFreshRawMemories(hippoRoot: string, count: number, t
|
|
|
28
24
|
export declare function loadAllEntries(hippoRoot: string, tenantId?: string): MemoryEntry[];
|
|
29
25
|
/** Every tenant's memory ids in loadAllEntries' order, for a caller that reads the rows a page at a time instead of holding them all. */
|
|
30
26
|
export declare function loadAllEntryIds(hippoRoot: string): string[];
|
|
27
|
+
/** How many memory rows the store holds across every tenant. */
|
|
28
|
+
export declare function countAllEntries(hippoRoot: string): number;
|
|
29
|
+
/** A superset, in loadAllEntries' order, of the rows whose lowercased content holds any of `tokens` or whose lowercased tags hold `tag`.
|
|
30
|
+
* The caller re-checks each row exactly; this only spares decoding rows that cannot match. */
|
|
31
|
+
export declare function loadEntriesMentioning(hippoRoot: string, tokens: readonly string[], tag: string, tenantId?: string): MemoryEntry[];
|
|
32
|
+
export interface EntryTextKey {
|
|
33
|
+
id: string;
|
|
34
|
+
tenant_id: string;
|
|
35
|
+
content: string;
|
|
36
|
+
source: string;
|
|
37
|
+
}
|
|
38
|
+
/** The rows in loadAllEntries' order (every tenant unless one is named), with only the columns that say whether another store already holds each. */
|
|
39
|
+
export declare function loadEntryTextKeys(hippoRoot: string, tenantId?: string): EntryTextKey[];
|
|
31
40
|
export interface EntriesWithBase {
|
|
32
41
|
entries: MemoryEntry[];
|
|
33
42
|
base: {
|
|
@@ -36,8 +45,30 @@ export interface EntriesWithBase {
|
|
|
36
45
|
}
|
|
37
46
|
/** Every entry plus a by-id lookup of each as loaded, rebuilt from its row on first use, so no deep copy of the store is kept. */
|
|
38
47
|
export declare function loadAllEntriesWithBase(hippoRoot: string): EntriesWithBase;
|
|
48
|
+
/** Where a page stopped: the `created`, `id` of its last row, in loadAllEntries' order. */
|
|
49
|
+
export interface EntryCursor {
|
|
50
|
+
created: string;
|
|
51
|
+
id: string;
|
|
52
|
+
}
|
|
53
|
+
export interface EntryPage {
|
|
54
|
+
entries: MemoryEntry[];
|
|
55
|
+
/** The cursor that reads the page after this one, or null when this was the last. */
|
|
56
|
+
next: EntryCursor | null;
|
|
57
|
+
}
|
|
58
|
+
/** Up to `limit` rows in loadAllEntries' order, starting after `after`; omitting `tenantId` reads every tenant. */
|
|
59
|
+
export declare function loadEntriesPage(hippoRoot: string, tenantId: string | undefined, page: {
|
|
60
|
+
limit: number;
|
|
61
|
+
after?: EntryCursor;
|
|
62
|
+
}): EntryPage;
|
|
39
63
|
/** Every memory row on an open connection, so a caller can read inside its own transaction. */
|
|
40
64
|
export declare function selectAllEntries(db: DatabaseSyncLike, tenantId?: string): MemoryEntry[];
|
|
65
|
+
/** The columns a text match needs, for every row of a tenant in loadAllEntries' order: callers read whole rows only for the ids that match. */
|
|
66
|
+
export declare function selectTenantTexts(db: DatabaseSyncLike, tenantId: string): Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
content: string;
|
|
69
|
+
source: string;
|
|
70
|
+
scope: string | null;
|
|
71
|
+
}>;
|
|
41
72
|
/** Live rows whose source starts with `prefix`, on the caller's handle; LIKE folds case, so the prefix is checked again exactly. */
|
|
42
73
|
export declare function selectLiveEntriesBySourcePrefix(db: DatabaseSyncLike, tenantId: string, prefix: string): MemoryEntry[];
|
|
43
74
|
export declare function loadContentsWithTag(hippoRoot: string, tenantId: string, tag: string, origins?: readonly string[]): string[];
|
|
@@ -3,7 +3,10 @@ import { MEMORY_SELECT_COLUMNS, rowToEntry, parseJsonArray } from './rows.js';
|
|
|
3
3
|
import { onHandle, openStore } from './open.js';
|
|
4
4
|
import { escapeLike } from '../util/escape.js';
|
|
5
5
|
import { originInSql } from '../core/project-identity.js';
|
|
6
|
-
import { scopeAdmitSql } from './
|
|
6
|
+
import { scopeAdmitSql } from './rule-sql.js';
|
|
7
|
+
import { chunked } from '../util/chunked.js';
|
|
8
|
+
import { DEFAULT_TENANT_ID } from '../util/env.js';
|
|
9
|
+
import { placeholders } from '../util/sql.js';
|
|
7
10
|
const MAX_IDS_PER_READ = 500;
|
|
8
11
|
// The plus keeps SQLite on the primary key for an id list: with a bare tenant_id it walks every row of the tenant instead.
|
|
9
12
|
export const TENANT_IS = '+tenant_id = ?';
|
|
@@ -18,15 +21,6 @@ export function readEntry(hippoRoot, id, tenantId) {
|
|
|
18
21
|
return row ? rowToEntry(row) : null;
|
|
19
22
|
}, openStore);
|
|
20
23
|
}
|
|
21
|
-
/** Ids per `IN (...)` list: far under SQLite's bound-parameter limit, with room for the tenant filter. */
|
|
22
|
-
export const ID_CHUNK = 500;
|
|
23
|
-
/** `items` in consecutive slices of at most `size`. */
|
|
24
|
-
export function chunked(items, size = ID_CHUNK) {
|
|
25
|
-
const out = [];
|
|
26
|
-
for (let i = 0; i < items.length; i += size)
|
|
27
|
-
out.push(items.slice(i, i + size));
|
|
28
|
-
return out;
|
|
29
|
-
}
|
|
30
24
|
/** Answers whether a tenant's rows in this store hold an id: `ids` are looked up now, one query per chunk, and any other id on its first ask. */
|
|
31
25
|
export function heldIdLookup(hippoRoot, tenantId, ids) {
|
|
32
26
|
const held = new Map();
|
|
@@ -36,7 +30,7 @@ export function heldIdLookup(hippoRoot, tenantId, ids) {
|
|
|
36
30
|
for (const id of chunk)
|
|
37
31
|
held.set(id, false);
|
|
38
32
|
// SAFETY: rows' shape matches the single `id` column selected.
|
|
39
|
-
const rows = db.prepare(`SELECT id FROM memories WHERE id IN (${chunk.
|
|
33
|
+
const rows = db.prepare(`SELECT id FROM memories WHERE id IN (${placeholders(chunk.length)}) AND ${TENANT_IS}`).all(...chunk, tenantId);
|
|
40
34
|
for (const row of rows)
|
|
41
35
|
held.set(row.id, true);
|
|
42
36
|
}
|
|
@@ -56,9 +50,9 @@ export function selectEntriesByIds(db, ids, tenantId) {
|
|
|
56
50
|
const tenantClause = tenantId !== undefined ? ` AND ${TENANT_IS}` : '';
|
|
57
51
|
const tenantArgs = tenantId !== undefined ? [tenantId] : [];
|
|
58
52
|
for (const chunk of chunked([...new Set(ids)])) {
|
|
59
|
-
const
|
|
53
|
+
const marks = placeholders(chunk.length);
|
|
60
54
|
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
61
|
-
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${
|
|
55
|
+
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${marks})${tenantClause}`).all(...chunk, ...tenantArgs);
|
|
62
56
|
for (const row of rows)
|
|
63
57
|
byId.set(row.id, rowToEntry(row));
|
|
64
58
|
}
|
|
@@ -70,9 +64,9 @@ export function selectChildrenByParent(db, parentIds, tenantId) {
|
|
|
70
64
|
const tenantClause = tenantId !== undefined ? ` AND ${TENANT_IS}` : '';
|
|
71
65
|
const tenantArgs = tenantId !== undefined ? [tenantId] : [];
|
|
72
66
|
for (const chunk of chunked([...new Set(parentIds)])) {
|
|
73
|
-
const
|
|
67
|
+
const marks = placeholders(chunk.length);
|
|
74
68
|
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
75
|
-
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE dag_parent_id IN (${
|
|
69
|
+
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE dag_parent_id IN (${marks})${tenantClause} ORDER BY created ASC, id ASC`).all(...chunk, ...tenantArgs);
|
|
76
70
|
for (const row of rows) {
|
|
77
71
|
const entry = rowToEntry(row);
|
|
78
72
|
const parentId = entry.dag_parent_id ?? '';
|
|
@@ -91,12 +85,12 @@ export function loadEntriesByIds(hippoRoot, ids, tenantId) {
|
|
|
91
85
|
return [];
|
|
92
86
|
const capped = ids.slice(0, MAX_IDS_PER_READ);
|
|
93
87
|
return onHandle(hippoRoot, (db) => {
|
|
94
|
-
const
|
|
88
|
+
const marks = placeholders(capped.length);
|
|
95
89
|
// Without ORDER BY, rows follow SQLite's IN(...) scan order, undefined w.r.t. `ids`.
|
|
96
90
|
// SAFETY: both branches select exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
97
91
|
const rows = tenantId !== undefined
|
|
98
|
-
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${
|
|
99
|
-
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${
|
|
92
|
+
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${marks}) AND ${TENANT_IS} ORDER BY created ASC, content ASC, id ASC`).all(...capped, tenantId)
|
|
93
|
+
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${marks}) ORDER BY created ASC, content ASC, id ASC`).all(...capped);
|
|
100
94
|
return rows.map(rowToEntry);
|
|
101
95
|
}, openStore);
|
|
102
96
|
}
|
|
@@ -201,6 +195,50 @@ export function loadAllEntryIds(hippoRoot) {
|
|
|
201
195
|
return db.prepare('SELECT id FROM memories ORDER BY created ASC, id ASC').all().map((row) => row.id);
|
|
202
196
|
}, openStore);
|
|
203
197
|
}
|
|
198
|
+
/** How many memory rows the store holds across every tenant. */
|
|
199
|
+
export function countAllEntries(hippoRoot) {
|
|
200
|
+
return onHandle(hippoRoot, (db) => {
|
|
201
|
+
// SAFETY: row's shape matches the single `COUNT(*) AS c` column.
|
|
202
|
+
const row = db.prepare('SELECT COUNT(*) AS c FROM memories').get();
|
|
203
|
+
return Number(row?.c ?? 0);
|
|
204
|
+
}, openStore);
|
|
205
|
+
}
|
|
206
|
+
// The only code points whose JS toLowerCase yields ASCII, which SQLite's ASCII-only LIKE folding cannot see.
|
|
207
|
+
const FOLDS_TO_ASCII = ['\u0130', '\u212A'];
|
|
208
|
+
/** A superset, in loadAllEntries' order, of the rows whose lowercased content holds any of `tokens` or whose lowercased tags hold `tag`.
|
|
209
|
+
* The caller re-checks each row exactly; this only spares decoding rows that cannot match. */
|
|
210
|
+
export function loadEntriesMentioning(hippoRoot, tokens, tag, tenantId) {
|
|
211
|
+
const likes = [...new Set(tokens)].map((t) => `%${escapeLike(t)}%`);
|
|
212
|
+
const clauses = likes.map(() => `content LIKE ? ESCAPE '\\'`);
|
|
213
|
+
const params = [...likes];
|
|
214
|
+
// A tag needing JSON escapes or case folding past ASCII is not found by a substring of tags_json, so every tagged row stays in.
|
|
215
|
+
if (/^[\x20-\x7e]*$/.test(tag) && !/["\\]/.test(tag)) {
|
|
216
|
+
clauses.push(`tags_json LIKE ? ESCAPE '\\'`);
|
|
217
|
+
params.push(`%${escapeLike(tag)}%`);
|
|
218
|
+
}
|
|
219
|
+
else
|
|
220
|
+
clauses.push(`COALESCE(tags_json, '[]') != '[]'`);
|
|
221
|
+
for (const ch of FOLDS_TO_ASCII) {
|
|
222
|
+
clauses.push('instr(content, ?) > 0', 'instr(tags_json, ?) > 0');
|
|
223
|
+
params.push(ch, ch);
|
|
224
|
+
}
|
|
225
|
+
const tenantClause = tenantId !== undefined ? 'tenant_id = ? AND ' : '';
|
|
226
|
+
return onHandle(hippoRoot, (db) => {
|
|
227
|
+
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
228
|
+
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE ${tenantClause}(${clauses.join(' OR ')}) ORDER BY created ASC, id ASC`).all(...(tenantId !== undefined ? [tenantId] : []), ...params);
|
|
229
|
+
return rows.map(rowToEntry);
|
|
230
|
+
}, openStore);
|
|
231
|
+
}
|
|
232
|
+
/** The rows in loadAllEntries' order (every tenant unless one is named), with only the columns that say whether another store already holds each. */
|
|
233
|
+
export function loadEntryTextKeys(hippoRoot, tenantId) {
|
|
234
|
+
return onHandle(hippoRoot, (db) => {
|
|
235
|
+
const where = tenantId !== undefined ? 'WHERE tenant_id = ? ' : '';
|
|
236
|
+
// SAFETY: rows' shape matches the four columns named in the SELECT.
|
|
237
|
+
const rows = db.prepare(`SELECT id, tenant_id, content, source FROM memories ${where}ORDER BY created ASC, id ASC`)
|
|
238
|
+
.all(...(tenantId !== undefined ? [tenantId] : []));
|
|
239
|
+
return rows.map((row) => ({ id: row.id, tenant_id: row.tenant_id ?? DEFAULT_TENANT_ID, content: row.content, source: row.source }));
|
|
240
|
+
}, openStore);
|
|
241
|
+
}
|
|
204
242
|
/** Every entry plus a by-id lookup of each as loaded, rebuilt from its row on first use, so no deep copy of the store is kept. */
|
|
205
243
|
export function loadAllEntriesWithBase(hippoRoot) {
|
|
206
244
|
const db = openStore(hippoRoot);
|
|
@@ -229,10 +267,38 @@ function selectAllRows(db, tenantId) {
|
|
|
229
267
|
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE tenant_id = ? ORDER BY created ASC, id ASC`).all(tenantId)
|
|
230
268
|
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories ORDER BY created ASC, id ASC`).all();
|
|
231
269
|
}
|
|
270
|
+
/** Up to `limit` rows in loadAllEntries' order, starting after `after`; omitting `tenantId` reads every tenant. */
|
|
271
|
+
export function loadEntriesPage(hippoRoot, tenantId, page) {
|
|
272
|
+
const where = [];
|
|
273
|
+
const params = [];
|
|
274
|
+
if (tenantId !== undefined) {
|
|
275
|
+
where.push('tenant_id = ?');
|
|
276
|
+
params.push(tenantId);
|
|
277
|
+
}
|
|
278
|
+
if (page.after) {
|
|
279
|
+
where.push('(created > ? OR (created = ? AND id > ?))');
|
|
280
|
+
params.push(page.after.created, page.after.created, page.after.id);
|
|
281
|
+
}
|
|
282
|
+
const clause = where.length > 0 ? `WHERE ${where.join(' AND ')} ` : '';
|
|
283
|
+
// One extra row says whether another page follows without a count.
|
|
284
|
+
params.push(page.limit + 1);
|
|
285
|
+
return onHandle(hippoRoot, (db) => {
|
|
286
|
+
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
287
|
+
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories ${clause}ORDER BY created ASC, id ASC LIMIT ?`).all(...params);
|
|
288
|
+
const entries = rows.slice(0, page.limit).map(rowToEntry);
|
|
289
|
+
const last = entries[entries.length - 1];
|
|
290
|
+
return { entries, next: rows.length > page.limit && last ? { created: last.created, id: last.id } : null };
|
|
291
|
+
}, openStore);
|
|
292
|
+
}
|
|
232
293
|
/** Every memory row on an open connection, so a caller can read inside its own transaction. */
|
|
233
294
|
export function selectAllEntries(db, tenantId) {
|
|
234
295
|
return selectAllRows(db, tenantId).map(rowToEntry);
|
|
235
296
|
}
|
|
297
|
+
/** The columns a text match needs, for every row of a tenant in loadAllEntries' order: callers read whole rows only for the ids that match. */
|
|
298
|
+
export function selectTenantTexts(db, tenantId) {
|
|
299
|
+
// SAFETY: rows' shape matches the four columns named in the SELECT.
|
|
300
|
+
return db.prepare('SELECT id, content, source, scope FROM memories WHERE tenant_id = ? ORDER BY created ASC, id ASC').all(tenantId);
|
|
301
|
+
}
|
|
236
302
|
/** Live rows whose source starts with `prefix`, on the caller's handle; LIKE folds case, so the prefix is checked again exactly. */
|
|
237
303
|
export function selectLiveEntriesBySourcePrefix(db, tenantId, prefix) {
|
|
238
304
|
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
@@ -265,7 +331,8 @@ export function loadVaultRawRows(hippoRoot, likeParam, tenantId) {
|
|
|
265
331
|
export function selectPreviewRows(db, columns, tenantId) {
|
|
266
332
|
const tenant = columns.has('tenant_id') ? ' WHERE tenant_id = ?' : '';
|
|
267
333
|
const column = (name, fallback) => (columns.has(name) ? name : `${fallback} AS ${name}`);
|
|
268
|
-
const statement = db.prepare(`SELECT id, content, ${column('source', "''")}, ${column('confidence', 'NULL')}, ${column('extracted_from', 'NULL')},
|
|
334
|
+
const statement = db.prepare(`SELECT id, content, ${column('source', "''")}, ${column('confidence', 'NULL')}, ${column('extracted_from', 'NULL')}, ` +
|
|
335
|
+
`${column('dag_level', '0')}, ${column('tags_json', "'[]'")} FROM memories${tenant}`);
|
|
269
336
|
// SAFETY: the SELECT names every PreviewRow field, each a literal fallback when its column is missing.
|
|
270
337
|
return (tenant ? statement.all(tenantId) : statement.all());
|
|
271
338
|
}
|
package/dist/store/entry-row.js
CHANGED
|
@@ -3,8 +3,15 @@ import { closeHippoDb, ftsRowCounts, openHippoDb, isFtsAvailable, repairFtsDrift
|
|
|
3
3
|
import { fallbackOrigin, originFromSource } from '../core/project-identity.js';
|
|
4
4
|
import { checkRejectionGuard } from './rejection.js';
|
|
5
5
|
import { errorMessage, log } from '../util/log.js';
|
|
6
|
+
/** A 1.x JS caller's `tenantId` would otherwise fall through to the default tenant without a sound. */
|
|
7
|
+
function rejectLegacyTenantKey(entry) {
|
|
8
|
+
if (Object.hasOwn(entry, 'tenantId') && entry.tenant_id === undefined) {
|
|
9
|
+
throw new TypeError('tenantId was renamed to tenant_id in 2.0');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
6
12
|
export function upsertEntryRow(db, entry) {
|
|
7
|
-
|
|
13
|
+
rejectLegacyTenantKey(entry);
|
|
14
|
+
checkRejectionGuard(db, entry.tenant_id ?? DEFAULT_TENANT_ID, entry.id, entry.content);
|
|
8
15
|
syncFtsRow(db, entry, upsertMemoryRow(db, entry));
|
|
9
16
|
}
|
|
10
17
|
/** The row alone, with no rejection guard or full-text row, for `upsertEntryRow` and for
|
|
@@ -104,7 +111,7 @@ function memoryRowValues(entry) {
|
|
|
104
111
|
entry.scope ?? null,
|
|
105
112
|
entry.owner ?? null,
|
|
106
113
|
entry.artifact_ref ?? null,
|
|
107
|
-
entry.
|
|
114
|
+
entry.tenant_id ?? DEFAULT_TENANT_ID,
|
|
108
115
|
entry.origin_project ?? null,
|
|
109
116
|
entry.descendant_count ?? 0,
|
|
110
117
|
entry.earliest_at ?? null,
|
|
@@ -2,28 +2,31 @@ import { type MemoryEntry } from '../core/memory.js';
|
|
|
2
2
|
import { type DatabaseSyncLike } from '../db/index.js';
|
|
3
3
|
export interface WriteEntryOptions {
|
|
4
4
|
actor?: string;
|
|
5
|
-
afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
|
|
6
5
|
/** Runs after the row commits and before the mirrors, on an idle connection; keep it best-effort. */
|
|
7
6
|
afterCommit?: () => void;
|
|
8
7
|
}
|
|
9
|
-
/**
|
|
10
|
-
|
|
8
|
+
/** Store-side only, never exported from a package entry: `afterWrite` hands the write's own db handle to the hook. */
|
|
9
|
+
export interface WriteEntryInternalOptions extends WriteEntryOptions {
|
|
10
|
+
/** Runs in the same SAVEPOINT as the INSERT, so a throw rolls the row back. */
|
|
11
|
+
afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
|
|
12
|
+
}
|
|
13
|
+
/** Write an entry to SQLite and refresh mirrors. `opts.actor` defaults to 'cli'; the api layer passes the resolved actor,
|
|
14
|
+
* so the audit log gets one row per write. */
|
|
11
15
|
export declare function writeEntry(hippoRoot: string, entry: MemoryEntry, opts?: WriteEntryOptions): void;
|
|
16
|
+
/** writeEntry for store code that needs the write's own handle: `opts.afterWrite` shares the INSERT's SAVEPOINT. */
|
|
17
|
+
export declare function writeEntryWithHook(hippoRoot: string, entry: MemoryEntry, opts?: WriteEntryInternalOptions): void;
|
|
12
18
|
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
13
|
-
* keeps its audit row, and mirrors follow the commit. Returns how many were written. */
|
|
19
|
+
* keeps its audit row, and mirrors follow the commit. Returns how many were written; an empty list opens no store. */
|
|
14
20
|
export declare function writeEntriesTogether(hippoRoot: string, entries: readonly MemoryEntry[]): number;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
export declare function
|
|
21
|
+
/** Runs `fill` in one transaction; each `put` writes one entry and returns false when the store rejects its value,
|
|
22
|
+
* leaving that row's refusal audit and the rest of the batch. Mirrors follow the commit. Returns how many were written. */
|
|
23
|
+
export declare function writeEntriesSkippingRejected(hippoRoot: string, fill: (put: (entry: MemoryEntry) => boolean) => void, actor?: string): number;
|
|
18
24
|
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
19
25
|
* on one open store and committed alone; an id the tenant does not hold is skipped. */
|
|
20
26
|
export declare function addTagToEntries(hippoRoot: string, tenantId: string, ids: readonly string[], tag: string): void;
|
|
21
27
|
/** DB-only write path: upsert, afterWrite hook and audit row inside one withWriteScope; the caller owns `db` and must call `writeEntryMirrors` after any
|
|
22
28
|
* outer tx commits, so a rolled-back tx never leaves orphan markdown. The audit row commits atomically with the INSERT. */
|
|
23
|
-
export declare function writeEntryDbOnly(db: DatabaseSyncLike, entry: MemoryEntry, opts?:
|
|
24
|
-
actor?: string;
|
|
25
|
-
afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
|
|
26
|
-
}): void;
|
|
29
|
+
export declare function writeEntryDbOnly(db: DatabaseSyncLike, entry: MemoryEntry, opts?: Pick<WriteEntryInternalOptions, 'actor' | 'afterWrite'>): void;
|
|
27
30
|
/** What follows a row's upsert inside its write scope: the remember row, last of the write's audit rows, then the summary parent's dirty mark. */
|
|
28
31
|
export declare function auditEntryWrite(db: DatabaseSyncLike, entry: MemoryEntry, actor: string): void;
|
|
29
32
|
/** Markdown mirror path, invoked AFTER commit (a rolled-back tx must leave no orphan markdown). */
|
|
@@ -36,7 +39,7 @@ export interface StrengthenOptions {
|
|
|
36
39
|
/** Strengthen what a read returned: update only the four retrieval columns on the live row, never a stale copy.
|
|
37
40
|
* Best effort: a failure logs and never fails the read. Returns the ids found in this store. */
|
|
38
41
|
export declare function strengthenRetrieved(hippoRoot: string, ids: readonly string[], opts: StrengthenOptions): Set<string>;
|
|
39
|
-
/** strengthenRetrieved on an open handle
|
|
42
|
+
/** strengthenRetrieved on an open handle in its own write scope, a savepoint inside a caller's transaction, so a recall's last writes share one handle. */
|
|
40
43
|
export declare function strengthenRetrievedInOwnTx(db: DatabaseSyncLike, ids: readonly string[], opts: StrengthenOptions): Set<string>;
|
|
41
44
|
/** strengthenRetrieved on the caller's handle, inside the caller's transaction. Throws; the caller decides. */
|
|
42
45
|
export declare function strengthenRetrievedOn(db: DatabaseSyncLike, ids: readonly string[], opts: StrengthenOptions): Set<string>;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { strengthAblation } from '../core/ablation.js';
|
|
1
2
|
import { markRetrieved } from '../core/memory.js';
|
|
2
|
-
import { closeHippoDb, openHippoDb,
|
|
3
|
-
import {
|
|
3
|
+
import { closeHippoDb, openHippoDb, withWriteScope } from '../db/index.js';
|
|
4
|
+
import { rethrowIfSqliteBlocked } from '../util/sqlite-blocked.js';
|
|
5
|
+
import { chunked } from '../util/chunked.js';
|
|
6
|
+
import { RejectedValueError } from '../core/api-errors.js';
|
|
4
7
|
import { markSummaryDirtyInTx } from './summary-dirty.js';
|
|
5
8
|
import { errorMessage, log } from '../util/log.js';
|
|
6
9
|
import { auditRejectionRefusal, audit } from './audit-event.js';
|
|
@@ -8,16 +11,22 @@ import { selectEntriesByIds } from './entry-reads.js';
|
|
|
8
11
|
import { stampOriginProject, upsertEntryRow, syncFtsRow, deleteFtsRow } from './entry-row.js';
|
|
9
12
|
import { mirrorBestEffort, writeMarkdownMirror } from './mirrors.js';
|
|
10
13
|
import { onHandle, openStore } from './open.js';
|
|
11
|
-
/** Write an entry to SQLite and refresh mirrors
|
|
12
|
-
*
|
|
14
|
+
/** Write an entry to SQLite and refresh mirrors. `opts.actor` defaults to 'cli'; the api layer passes the resolved actor,
|
|
15
|
+
* so the audit log gets one row per write. */
|
|
13
16
|
export function writeEntry(hippoRoot, entry, opts) {
|
|
17
|
+
writeEntryWithHook(hippoRoot, entry, opts);
|
|
18
|
+
}
|
|
19
|
+
/** writeEntry for store code that needs the write's own handle: `opts.afterWrite` shares the INSERT's SAVEPOINT. */
|
|
20
|
+
export function writeEntryWithHook(hippoRoot, entry, opts) {
|
|
14
21
|
onHandle(hippoRoot, (db) => {
|
|
15
22
|
writeEntryOn(db, hippoRoot, entry, opts);
|
|
16
23
|
}, openStore);
|
|
17
24
|
}
|
|
18
25
|
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
19
|
-
* keeps its audit row, and mirrors follow the commit. Returns how many were written. */
|
|
26
|
+
* keeps its audit row, and mirrors follow the commit. Returns how many were written; an empty list opens no store. */
|
|
20
27
|
export function writeEntriesTogether(hippoRoot, entries) {
|
|
28
|
+
if (entries.length === 0)
|
|
29
|
+
return 0;
|
|
21
30
|
const stamped = entries.map((entry) => stampOriginProject(hippoRoot, entry));
|
|
22
31
|
const db = openStore(hippoRoot);
|
|
23
32
|
try {
|
|
@@ -39,15 +48,31 @@ export function writeEntriesTogether(hippoRoot, entries) {
|
|
|
39
48
|
}
|
|
40
49
|
return stamped.length;
|
|
41
50
|
}
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
export function
|
|
45
|
-
|
|
46
|
-
return;
|
|
51
|
+
/** Runs `fill` in one transaction; each `put` writes one entry and returns false when the store rejects its value,
|
|
52
|
+
* leaving that row's refusal audit and the rest of the batch. Mirrors follow the commit. Returns how many were written. */
|
|
53
|
+
export function writeEntriesSkippingRejected(hippoRoot, fill, actor = 'cli') {
|
|
54
|
+
const written = [];
|
|
47
55
|
onHandle(hippoRoot, (db) => {
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
withWriteScope(db, 'write_entries_skipping_rejected', () => {
|
|
57
|
+
fill((entry) => {
|
|
58
|
+
const stamped = stampOriginProject(hippoRoot, entry);
|
|
59
|
+
try {
|
|
60
|
+
writeEntryDbOnly(db, stamped, { actor });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!(error instanceof RejectedValueError))
|
|
64
|
+
throw error;
|
|
65
|
+
auditRejectionRefusal(db, error, actor);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
written.push(stamped);
|
|
69
|
+
return true;
|
|
70
|
+
});
|
|
71
|
+
});
|
|
50
72
|
}, openStore);
|
|
73
|
+
for (const entry of written)
|
|
74
|
+
writeEntryMirrors(hippoRoot, entry);
|
|
75
|
+
return written.length;
|
|
51
76
|
}
|
|
52
77
|
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
53
78
|
* on one open store and committed alone; an id the tenant does not hold is skipped. */
|
|
@@ -97,11 +122,11 @@ export function auditEntryWrite(db, entry, actor) {
|
|
|
97
122
|
audit(db, 'remember', { targetId: entry.id, metadata: {
|
|
98
123
|
kind: entry.kind ?? 'distilled',
|
|
99
124
|
scope: entry.scope ?? null,
|
|
100
|
-
}, actor, tenantId: entry.
|
|
125
|
+
}, actor, tenantId: entry.tenant_id });
|
|
101
126
|
// A child write marks its summary parent dirty for the sleep-cycle rebuild; most writes
|
|
102
127
|
// have no parent, so the hot path pays one null check.
|
|
103
128
|
if (entry.dag_parent_id) {
|
|
104
|
-
markSummaryDirtyInTx(db, entry.dag_parent_id, entry.
|
|
129
|
+
markSummaryDirtyInTx(db, entry.dag_parent_id, entry.tenant_id, actor);
|
|
105
130
|
}
|
|
106
131
|
}
|
|
107
132
|
/** Markdown mirror path, invoked AFTER commit (a rolled-back tx must leave no orphan markdown). */
|
|
@@ -129,7 +154,7 @@ export function strengthenRetrieved(hippoRoot, ids, opts) {
|
|
|
129
154
|
closeHippoDb(db);
|
|
130
155
|
}
|
|
131
156
|
}
|
|
132
|
-
/** strengthenRetrieved on an open handle
|
|
157
|
+
/** strengthenRetrieved on an open handle in its own write scope, a savepoint inside a caller's transaction, so a recall's last writes share one handle. */
|
|
133
158
|
export function strengthenRetrievedInOwnTx(db, ids, opts) {
|
|
134
159
|
if (ids.length === 0 || opts.recallBoostAblated)
|
|
135
160
|
return new Set();
|
|
@@ -144,6 +169,8 @@ export function strengthenRetrievedInOwnTx(db, ids, opts) {
|
|
|
144
169
|
function warnStrengthenFailed(error) {
|
|
145
170
|
log.warn(`retrieval stats not saved (${errorMessage(error)})`);
|
|
146
171
|
}
|
|
172
|
+
/** Rows per recall-write statement: five bound values each, far under SQLite's parameter limit. */
|
|
173
|
+
const RETRIEVAL_UPDATE_CHUNK = 100;
|
|
147
174
|
/** strengthenRetrieved on the caller's handle, inside the caller's transaction. Throws; the caller decides. */
|
|
148
175
|
export function strengthenRetrievedOn(db, ids, opts) {
|
|
149
176
|
const found = new Set();
|
|
@@ -151,25 +178,30 @@ export function strengthenRetrievedOn(db, ids, opts) {
|
|
|
151
178
|
return found;
|
|
152
179
|
const byId = selectEntriesByIds(db, ids, opts.tenantId);
|
|
153
180
|
const live = [...new Set(ids)].flatMap((id) => byId.get(id) ?? []);
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
const updated = markRetrieved(live, undefined, { ablation: strengthAblation() });
|
|
182
|
+
// One UPDATE ... FROM per chunk of rows instead of one statement per row.
|
|
183
|
+
for (const chunk of chunked(updated, RETRIEVAL_UPDATE_CHUNK)) {
|
|
184
|
+
const values = chunk.map(() => '(?, ?, ?, ?, ?)').join(', ');
|
|
185
|
+
db.prepare(`WITH v(id, rc, lr, hl, st) AS (VALUES ${values})
|
|
186
|
+
UPDATE memories SET retrieval_count = v.rc, last_retrieved = v.lr, half_life_days = v.hl, strength = v.st
|
|
187
|
+
FROM v WHERE memories.id = v.id`).run(...chunk.flatMap((e) => [e.id, e.retrieval_count, e.last_retrieved, e.half_life_days, e.strength]));
|
|
188
|
+
for (const e of chunk)
|
|
189
|
+
found.add(e.id);
|
|
158
190
|
}
|
|
159
191
|
return found;
|
|
160
192
|
}
|
|
161
193
|
/** Rewrites a live row's tags and its full-text row on the caller's transaction, with no audit row. */
|
|
162
194
|
export function setEntryTagsInTx(db, entry) {
|
|
163
195
|
db.prepare(`UPDATE memories SET tags_json = ?, updated_at = datetime('now') WHERE id = ? AND tenant_id = ?`)
|
|
164
|
-
.run(JSON.stringify(entry.tags), entry.id, entry.
|
|
196
|
+
.run(JSON.stringify(entry.tags), entry.id, entry.tenant_id);
|
|
165
197
|
syncFtsRow(db, entry);
|
|
166
198
|
}
|
|
167
199
|
/** Removes a row from `memories` and full-text search on the caller's transaction, as sleep's dormant move does, and marks its summary parent dirty. */
|
|
168
200
|
export function deleteEntryRowInTx(db, entry, actor) {
|
|
169
|
-
db.prepare('DELETE FROM memories WHERE id = ? AND tenant_id = ?').run(entry.id, entry.
|
|
201
|
+
db.prepare('DELETE FROM memories WHERE id = ? AND tenant_id = ?').run(entry.id, entry.tenant_id);
|
|
170
202
|
deleteFtsRow(db, entry.id);
|
|
171
203
|
if (entry.dag_parent_id)
|
|
172
|
-
markSummaryDirtyInTx(db, entry.dag_parent_id, entry.
|
|
204
|
+
markSummaryDirtyInTx(db, entry.dag_parent_id, entry.tenant_id, actor);
|
|
173
205
|
}
|
|
174
206
|
/** One half-life per memory id, on the caller's transaction. */
|
|
175
207
|
export function setHalfLivesAt(db, rows) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type FailureEvent, type FailureOutcome } from './failure-log.js';
|
|
2
|
+
/** {@link recordFailure} on a handle of its own. */
|
|
3
|
+
export declare function recordFailureAt(hippoRoot: string, event: FailureEvent): number;
|
|
4
|
+
/** {@link requestOutcome} on a handle of its own. */
|
|
5
|
+
export declare function requestOutcomeAt(hippoRoot: string, tenantId: string, requestId: string, sessionId: string): FailureOutcome | null;
|
|
6
|
+
/** {@link settleFailureOutcome} on a handle of its own. */
|
|
7
|
+
export declare function settleFailureOutcomeAt(hippoRoot: string, tenantId: string, requestId: string, outcome: FailureOutcome): void;
|
|
8
|
+
//# sourceMappingURL=failure-log-at.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The failure log on a handle of its own, for code that has a folder and no connection.
|
|
2
|
+
import { onHandle } from './open.js';
|
|
3
|
+
import { recordFailure, requestOutcome, settleFailureOutcome } from './failure-log.js';
|
|
4
|
+
/** {@link recordFailure} on a handle of its own. */
|
|
5
|
+
export function recordFailureAt(hippoRoot, event) {
|
|
6
|
+
return onHandle(hippoRoot, (db) => recordFailure(db, event));
|
|
7
|
+
}
|
|
8
|
+
/** {@link requestOutcome} on a handle of its own. */
|
|
9
|
+
export function requestOutcomeAt(hippoRoot, tenantId, requestId, sessionId) {
|
|
10
|
+
return onHandle(hippoRoot, (db) => requestOutcome(db, tenantId, requestId, sessionId));
|
|
11
|
+
}
|
|
12
|
+
/** {@link settleFailureOutcome} on a handle of its own. */
|
|
13
|
+
export function settleFailureOutcomeAt(hippoRoot, tenantId, requestId, outcome) {
|
|
14
|
+
onHandle(hippoRoot, (db) => settleFailureOutcome(db, tenantId, requestId, outcome));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=failure-log-at.js.map
|
|
@@ -28,8 +28,8 @@ export interface FailureEvent {
|
|
|
28
28
|
/** Override the timestamp (tests). ISO string. */
|
|
29
29
|
now?: string;
|
|
30
30
|
}
|
|
31
|
-
/**
|
|
32
|
-
export declare function recordFailure(db: DatabaseSyncLike, event: FailureEvent):
|
|
31
|
+
/** Prune rows past {@link FAILURE_LOG_RETENTION_DAYS}, then append one failure row; returns the new row's id. */
|
|
32
|
+
export declare function recordFailure(db: DatabaseSyncLike, event: FailureEvent): number;
|
|
33
33
|
/** The outcome logged for a caller's request id, or null, so a retried send finds the first one; another session's id is a ConflictError. */
|
|
34
34
|
export declare function requestOutcome(db: DatabaseSyncLike, tenantId: string, requestId: string, sessionId: string): FailureOutcome | null;
|
|
35
35
|
/** A retry that stored what the first try could not rewrites that row, since the request id allows one row per tenant. */
|
|
@@ -5,14 +5,16 @@ import { DAY_MS } from '../util/time.js';
|
|
|
5
5
|
export const FAILURE_LOG_RETENTION_DAYS = 90;
|
|
6
6
|
/** Longest session id or tool name kept; the hook payload is not trusted to be short. */
|
|
7
7
|
const MAX_FIELD = 128;
|
|
8
|
-
/**
|
|
8
|
+
/** Prune rows past {@link FAILURE_LOG_RETENTION_DAYS}, then append one failure row; returns the new row's id. */
|
|
9
9
|
export function recordFailure(db, event) {
|
|
10
10
|
// Normalised, because the window and prune compare timestamps as strings.
|
|
11
11
|
const now = new Date(event.now ?? Date.now()).toISOString();
|
|
12
|
-
|
|
13
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(now, event.tenantId, event.sessionId?.slice(0, MAX_FIELD) ?? null, event.tool?.slice(0, MAX_FIELD) ?? null, event.outcome, event.rule ?? null, event.sigHash ?? null, event.detailHash ?? null, event.ownerSubject ?? null, event.originProject ?? null, event.requestId ?? null);
|
|
12
|
+
// Prune first: nothing after the insert can throw, so a returned id always means a committed row.
|
|
14
13
|
const cutoff = new Date(Date.parse(now) - FAILURE_LOG_RETENTION_DAYS * DAY_MS).toISOString();
|
|
15
14
|
db.prepare(`DELETE FROM failure_log WHERE ts < ?`).run(cutoff);
|
|
15
|
+
const inserted = db.prepare(`INSERT INTO failure_log (ts, tenant_id, session_id, tool, outcome, skip_rule, sig_hash, detail_hash, owner_subject, origin_project, request_id)
|
|
16
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(now, event.tenantId, event.sessionId?.slice(0, MAX_FIELD) ?? null, event.tool?.slice(0, MAX_FIELD) ?? null, event.outcome, event.rule ?? null, event.sigHash ?? null, event.detailHash ?? null, event.ownerSubject ?? null, event.originProject ?? null, event.requestId ?? null);
|
|
17
|
+
return Number(inserted.lastInsertRowid);
|
|
16
18
|
}
|
|
17
19
|
/** The outcome logged for a caller's request id, or null, so a retried send finds the first one; another session's id is a ConflictError. */
|
|
18
20
|
export function requestOutcome(db, tenantId, requestId, sessionId) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { DatabaseSyncLike } from '../db/index.js';
|
|
2
2
|
import type { MemoryEntry } from '../core/memory.js';
|
|
3
3
|
export type GatedWriteResult = 'written' | 'skipped:not-worth-storing' | 'skipped:secret' | 'skipped:rejected';
|
|
4
|
-
/** Runs on the caller's handle so it nests in the caller's transaction (writeEntry would open a second handle and wait on that lock); the
|
|
4
|
+
/** Runs on the caller's handle so it nests in the caller's transaction (writeEntry would open a second handle and wait on that lock); the
|
|
5
|
+
* caller mirrors after commit with an entry it stamped itself. The rejection audit lands inside that transaction, which is safe because
|
|
6
|
+
* a batch that rolls back stays `summarised` and replay writes the audit again. */
|
|
5
7
|
export declare function gatedWrite(db: DatabaseSyncLike, hippoRoot: string, entry: MemoryEntry, opts?: {
|
|
6
8
|
actor?: string;
|
|
7
9
|
worthCheck?: boolean;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// The one write path for text no person typed into hippo: capture, compaction items and imported agent memories.
|
|
2
2
|
import { isContentWorthStoring } from '../core/memory-quality.js';
|
|
3
|
-
import { RejectedValueError } from '../
|
|
3
|
+
import { RejectedValueError } from '../core/api-errors.js';
|
|
4
4
|
import { detectSecret } from '../util/secret-detect.js';
|
|
5
|
-
import { auditRejectionRefusal } from '
|
|
6
|
-
import { stampOriginProject } from '
|
|
7
|
-
import { writeEntryDbOnly } from '
|
|
8
|
-
/** Runs on the caller's handle so it nests in the caller's transaction (writeEntry would open a second handle and wait on that lock); the
|
|
5
|
+
import { auditRejectionRefusal } from './audit-event.js';
|
|
6
|
+
import { stampOriginProject } from './entry-row.js';
|
|
7
|
+
import { writeEntryDbOnly } from './entry-writes.js';
|
|
8
|
+
/** Runs on the caller's handle so it nests in the caller's transaction (writeEntry would open a second handle and wait on that lock); the
|
|
9
|
+
* caller mirrors after commit with an entry it stamped itself. The rejection audit lands inside that transaction, which is safe because
|
|
10
|
+
* a batch that rolls back stays `summarised` and replay writes the audit again. */
|
|
9
11
|
export function gatedWrite(db, hippoRoot, entry, opts) {
|
|
10
12
|
// Off for imported agent memories: a person wrote those notes, and a one-line preference fails the check.
|
|
11
13
|
if (opts?.worthCheck !== false && !isContentWorthStoring(entry.content))
|
package/dist/store/goals.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { withWriteScope } from '../db/index.js';
|
|
4
4
|
import { onHandle } from './open.js';
|
|
5
|
+
import { placeholders } from '../util/sql.js';
|
|
5
6
|
const MAX_ACTIVE_GOAL_DEPTH = 3;
|
|
6
7
|
export function rowToGoal(row) {
|
|
7
8
|
return {
|
|
@@ -146,26 +147,28 @@ function getActiveGoalsWithDb(db, opts) {
|
|
|
146
147
|
// Per-goal retrieval_policy multipliers compose onto the base goal-tag boost and are hard-capped at MAX_FINAL_MULTIPLIER (3.0x) before scoring.
|
|
147
148
|
function loadGoalPolicies(db, active) {
|
|
148
149
|
const policiesByGoalId = new Map();
|
|
150
|
+
const policyIds = [...new Set(active.flatMap((g) => (g.retrievalPolicyId ? [g.retrievalPolicyId] : [])))];
|
|
151
|
+
if (policyIds.length === 0)
|
|
152
|
+
return policiesByGoalId;
|
|
153
|
+
// SAFETY: the SELECT projects exactly these seven retrieval_policy columns; MAX_ACTIVE_GOAL_DEPTH bounds the IN list.
|
|
154
|
+
const rows = db.prepare(`
|
|
155
|
+
SELECT id, goal_id, policy_type, weight_schema_fit, weight_recency, weight_outcome, error_priority
|
|
156
|
+
FROM retrieval_policy WHERE id IN (${placeholders(policyIds.length)})
|
|
157
|
+
`).all(...policyIds);
|
|
158
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
149
159
|
for (const g of active) {
|
|
150
|
-
|
|
160
|
+
const row = g.retrievalPolicyId ? byId.get(g.retrievalPolicyId) : undefined;
|
|
161
|
+
if (!row)
|
|
151
162
|
continue;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
goalId: row.goal_id,
|
|
162
|
-
policyType: row.policy_type,
|
|
163
|
-
weightSchemaFit: row.weight_schema_fit,
|
|
164
|
-
weightRecency: row.weight_recency,
|
|
165
|
-
weightOutcome: row.weight_outcome,
|
|
166
|
-
errorPriority: row.error_priority,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
163
|
+
policiesByGoalId.set(g.id, {
|
|
164
|
+
id: row.id,
|
|
165
|
+
goalId: row.goal_id,
|
|
166
|
+
policyType: row.policy_type,
|
|
167
|
+
weightSchemaFit: row.weight_schema_fit,
|
|
168
|
+
weightRecency: row.weight_recency,
|
|
169
|
+
weightOutcome: row.weight_outcome,
|
|
170
|
+
errorPriority: row.error_priority,
|
|
171
|
+
});
|
|
169
172
|
}
|
|
170
173
|
return policiesByGoalId;
|
|
171
174
|
}
|
|
@@ -176,7 +179,7 @@ export function localGoalRecallRows(db, rows) {
|
|
|
176
179
|
return [];
|
|
177
180
|
const ids = [...new Set(rows.map((r) => r.memoryId))];
|
|
178
181
|
// SAFETY: the SELECT projects exactly one column, `id`, from memories.
|
|
179
|
-
const local = db.prepare(`SELECT id FROM memories WHERE id IN (${ids.
|
|
182
|
+
const local = db.prepare(`SELECT id FROM memories WHERE id IN (${placeholders(ids.length)})`).all(...ids);
|
|
180
183
|
const localIds = new Set(local.map((r) => r.id));
|
|
181
184
|
return rows.filter((r) => localIds.has(r.memoryId));
|
|
182
185
|
}
|