nlm-memory 0.21.0 → 0.21.13
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 +67 -12
- package/assets/replay-eval-dark.svg +26 -0
- package/assets/replay-eval-light.svg +26 -0
- package/dist/cli/digest.js +34 -7
- package/dist/cli/digest.js.map +1 -1
- package/dist/cli/nlm.d.ts +14 -0
- package/dist/cli/nlm.js +450 -65
- package/dist/cli/nlm.js.map +1 -1
- package/dist/cli/reprocess-job-adapters.d.ts +35 -0
- package/dist/cli/reprocess-job-adapters.js +80 -0
- package/dist/cli/reprocess-job-adapters.js.map +1 -0
- package/dist/cli/scope-coverage.js +4 -1
- package/dist/cli/scope-coverage.js.map +1 -1
- package/dist/cli/supersede.js +8 -7
- package/dist/cli/supersede.js.map +1 -1
- package/dist/core/actions/actions-log.d.ts +65 -8
- package/dist/core/actions/actions-log.js +134 -17
- package/dist/core/actions/actions-log.js.map +1 -1
- package/dist/core/actions/overlay.d.ts +11 -2
- package/dist/core/actions/overlay.js +18 -6
- package/dist/core/actions/overlay.js.map +1 -1
- package/dist/core/adapters/from-source.js +11 -3
- package/dist/core/adapters/from-source.js.map +1 -1
- package/dist/core/adapters/fs-wiki-writer.d.ts +44 -0
- package/dist/core/adapters/fs-wiki-writer.js +132 -0
- package/dist/core/adapters/fs-wiki-writer.js.map +1 -0
- package/dist/core/adapters/hermes-agent.d.ts +15 -2
- package/dist/core/adapters/hermes-agent.js +57 -11
- package/dist/core/adapters/hermes-agent.js.map +1 -1
- package/dist/core/adapters/memory-wiki-writer.d.ts +8 -0
- package/dist/core/adapters/memory-wiki-writer.js +16 -0
- package/dist/core/adapters/memory-wiki-writer.js.map +1 -0
- package/dist/core/adapters/muse.d.ts +51 -0
- package/dist/core/adapters/muse.js +271 -0
- package/dist/core/adapters/muse.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +11 -4
- package/dist/core/adapters/opencode.js +41 -7
- package/dist/core/adapters/opencode.js.map +1 -1
- package/dist/core/alerts/alert-state.d.ts +17 -0
- package/dist/core/alerts/alert-state.js +45 -0
- package/dist/core/alerts/alert-state.js.map +1 -0
- package/dist/core/alerts/check-and-alert.d.ts +28 -0
- package/dist/core/alerts/check-and-alert.js +53 -0
- package/dist/core/alerts/check-and-alert.js.map +1 -0
- package/dist/core/alerts/drift-transition.d.ts +27 -0
- package/dist/core/alerts/drift-transition.js +56 -0
- package/dist/core/alerts/drift-transition.js.map +1 -0
- package/dist/core/alerts/embedder-transition.d.ts +23 -0
- package/dist/core/alerts/embedder-transition.js +40 -0
- package/dist/core/alerts/embedder-transition.js.map +1 -0
- package/dist/core/alerts/fire-alert.d.ts +24 -0
- package/dist/core/alerts/fire-alert.js +72 -0
- package/dist/core/alerts/fire-alert.js.map +1 -0
- package/dist/core/alerts/job-alert.d.ts +12 -0
- package/dist/core/alerts/job-alert.js +37 -0
- package/dist/core/alerts/job-alert.js.map +1 -0
- package/dist/core/alerts/types.d.ts +104 -0
- package/dist/core/alerts/types.js +11 -0
- package/dist/core/alerts/types.js.map +1 -0
- package/dist/core/alerts/wiki-alert.d.ts +15 -0
- package/dist/core/alerts/wiki-alert.js +31 -0
- package/dist/core/alerts/wiki-alert.js.map +1 -0
- package/dist/core/classifier/prompt.d.ts +13 -0
- package/dist/core/classifier/prompt.js +52 -2
- package/dist/core/classifier/prompt.js.map +1 -1
- package/dist/core/dataset/build-dataset.d.ts +16 -1
- package/dist/core/dataset/build-dataset.js +105 -45
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/digest/compose.d.ts +8 -0
- package/dist/core/digest/compose.js +54 -0
- package/dist/core/digest/compose.js.map +1 -1
- package/dist/core/digest/hook-injection.d.ts +1 -1
- package/dist/core/digest/hook-injection.js +9 -1
- package/dist/core/digest/hook-injection.js.map +1 -1
- package/dist/core/digest/hook-version-parity.d.ts +31 -0
- package/dist/core/digest/hook-version-parity.js +56 -0
- package/dist/core/digest/hook-version-parity.js.map +1 -0
- package/dist/core/embedding/pg-embed-backfill.js +1 -1
- package/dist/core/embedding/pg-embed-backfill.js.map +1 -1
- package/dist/core/exemplars/capture-from-session.d.ts +1 -1
- package/dist/core/exemplars/capture-from-session.js +3 -3
- package/dist/core/exemplars/capture-from-session.js.map +1 -1
- package/dist/core/exemplars/embed-backfill.d.ts +9 -0
- package/dist/core/exemplars/embed-backfill.js +9 -1
- package/dist/core/exemplars/embed-backfill.js.map +1 -1
- package/dist/core/exemplars/recall-code.d.ts +1 -1
- package/dist/core/exemplars/recall-code.js +2 -2
- package/dist/core/exemplars/recall-code.js.map +1 -1
- package/dist/core/facts/backfill-facts.d.ts +1 -1
- package/dist/core/facts/backfill-facts.js +4 -4
- package/dist/core/facts/backfill-facts.js.map +1 -1
- package/dist/core/facts/embed-backfill.d.ts +54 -0
- package/dist/core/facts/embed-backfill.js +109 -0
- package/dist/core/facts/embed-backfill.js.map +1 -0
- package/dist/core/facts/reconcile-facts.d.ts +42 -0
- package/dist/core/facts/reconcile-facts.js +133 -0
- package/dist/core/facts/reconcile-facts.js.map +1 -0
- package/dist/core/health/embed-failure-state.d.ts +4 -0
- package/dist/core/health/embed-failure-state.js +12 -0
- package/dist/core/health/embed-failure-state.js.map +1 -0
- package/dist/core/health/warmup-retry.d.ts +27 -0
- package/dist/core/health/warmup-retry.js +53 -0
- package/dist/core/health/warmup-retry.js.map +1 -0
- package/dist/core/health/warmup-state.d.ts +15 -0
- package/dist/core/health/warmup-state.js +15 -1
- package/dist/core/health/warmup-state.js.map +1 -1
- package/dist/core/hook/cite-memo.d.ts +11 -7
- package/dist/core/hook/cite-memo.js +25 -17
- package/dist/core/hook/cite-memo.js.map +1 -1
- package/dist/core/hook/hook-log.d.ts +13 -2
- package/dist/core/hook/hook-log.js +16 -8
- package/dist/core/hook/hook-log.js.map +1 -1
- package/dist/core/hook/memo.d.ts +10 -6
- package/dist/core/hook/memo.js +25 -17
- package/dist/core/hook/memo.js.map +1 -1
- package/dist/core/hook/pointer-block.d.ts +8 -1
- package/dist/core/hook/pointer-block.js +17 -4
- package/dist/core/hook/pointer-block.js.map +1 -1
- package/dist/core/hook/resolve-conversation-by-query.d.ts +6 -5
- package/dist/core/hook/resolve-conversation-by-query.js +24 -12
- package/dist/core/hook/resolve-conversation-by-query.js.map +1 -1
- package/dist/core/ingest/ingest-session.d.ts +1 -1
- package/dist/core/ingest/ingest-session.js +3 -3
- package/dist/core/ingest/ingest-session.js.map +1 -1
- package/dist/core/ingest/reclassify-oversized.d.ts +1 -1
- package/dist/core/ingest/reclassify-oversized.js +2 -2
- package/dist/core/ingest/reclassify-oversized.js.map +1 -1
- package/dist/core/ingest/reprocess.d.ts +1 -1
- package/dist/core/ingest/reprocess.js +2 -2
- package/dist/core/ingest/reprocess.js.map +1 -1
- package/dist/core/jobs/job-supervisor.d.ts +168 -0
- package/dist/core/jobs/job-supervisor.js +335 -0
- package/dist/core/jobs/job-supervisor.js.map +1 -0
- package/dist/core/learner/model.d.ts +63 -0
- package/dist/core/learner/model.js +30 -0
- package/dist/core/learner/model.js.map +1 -0
- package/dist/core/learner/service.d.ts +42 -0
- package/dist/core/learner/service.js +74 -0
- package/dist/core/learner/service.js.map +1 -0
- package/dist/core/learner/summary.d.ts +28 -0
- package/dist/core/learner/summary.js +70 -0
- package/dist/core/learner/summary.js.map +1 -0
- package/dist/core/learner/validate.d.ts +18 -0
- package/dist/core/learner/validate.js +95 -0
- package/dist/core/learner/validate.js.map +1 -0
- package/dist/core/metrics/re-derivation.d.ts +31 -2
- package/dist/core/metrics/re-derivation.js +36 -4
- package/dist/core/metrics/re-derivation.js.map +1 -1
- package/dist/core/outcome/coverage.d.ts +1 -1
- package/dist/core/outcome/coverage.js +2 -2
- package/dist/core/outcome/coverage.js.map +1 -1
- package/dist/core/outcome/rollup.d.ts +1 -1
- package/dist/core/outcome/rollup.js +4 -4
- package/dist/core/outcome/rollup.js.map +1 -1
- package/dist/core/providers/provider-registry.d.ts +40 -23
- package/dist/core/providers/provider-registry.js +99 -81
- package/dist/core/providers/provider-registry.js.map +1 -1
- package/dist/core/recall/citation-log.d.ts +10 -5
- package/dist/core/recall/citation-log.js +21 -10
- package/dist/core/recall/citation-log.js.map +1 -1
- package/dist/core/recall/hook-recall-log.d.ts +5 -2
- package/dist/core/recall/hook-recall-log.js +12 -6
- package/dist/core/recall/hook-recall-log.js.map +1 -1
- package/dist/core/recall/miss-log.d.ts +7 -4
- package/dist/core/recall/miss-log.js +18 -11
- package/dist/core/recall/miss-log.js.map +1 -1
- package/dist/core/recall/query-log.d.ts +8 -5
- package/dist/core/recall/query-log.js +16 -9
- package/dist/core/recall/query-log.js.map +1 -1
- package/dist/core/recall/recall-service.d.ts +10 -1
- package/dist/core/recall/recall-service.js +31 -12
- package/dist/core/recall/recall-service.js.map +1 -1
- package/dist/core/recall/recent-log.d.ts +6 -1
- package/dist/core/recall/recent-log.js +13 -5
- package/dist/core/recall/recent-log.js.map +1 -1
- package/dist/core/recall/related-concepts.d.ts +29 -0
- package/dist/core/recall/related-concepts.js +67 -0
- package/dist/core/recall/related-concepts.js.map +1 -0
- package/dist/core/recall/related-exemplars.d.ts +1 -1
- package/dist/core/recall/related-exemplars.js +2 -2
- package/dist/core/recall/related-exemplars.js.map +1 -1
- package/dist/core/recall/related-facts.d.ts +1 -1
- package/dist/core/recall/related-facts.js +3 -3
- package/dist/core/recall/related-facts.js.map +1 -1
- package/dist/core/recall-facts/fact-query-log.d.ts +8 -4
- package/dist/core/recall-facts/fact-query-log.js +16 -8
- package/dist/core/recall-facts/fact-query-log.js.map +1 -1
- package/dist/core/recall-facts/fact-recall-service.d.ts +2 -2
- package/dist/core/recall-facts/fact-recall-service.js +12 -12
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
- package/dist/core/scheduler/scan-once.js +15 -14
- package/dist/core/scheduler/scan-once.js.map +1 -1
- package/dist/core/scheduler/scheduler.d.ts +3 -0
- package/dist/core/scheduler/scheduler.js +15 -11
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/signals/failure-mode-recall.d.ts +1 -1
- package/dist/core/signals/failure-mode-recall.js +2 -2
- package/dist/core/signals/failure-mode-recall.js.map +1 -1
- package/dist/core/signals/stamp-scope.d.ts +2 -2
- package/dist/core/signals/stamp-scope.js +2 -2
- package/dist/core/signals/stamp-scope.js.map +1 -1
- package/dist/core/sources/source-registry.d.ts +49 -28
- package/dist/core/sources/source-registry.js +113 -70
- package/dist/core/sources/source-registry.js.map +1 -1
- package/dist/core/storage/pg-code-exemplar-store.d.ts +19 -10
- package/dist/core/storage/pg-code-exemplar-store.js +58 -27
- package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/pg-entity-store.d.ts +6 -1
- package/dist/core/storage/pg-entity-store.js +33 -18
- package/dist/core/storage/pg-entity-store.js.map +1 -1
- package/dist/core/storage/pg-fact-ingest.d.ts +1 -1
- package/dist/core/storage/pg-fact-ingest.js +10 -7
- package/dist/core/storage/pg-fact-ingest.js.map +1 -1
- package/dist/core/storage/pg-fact-store.d.ts +29 -17
- package/dist/core/storage/pg-fact-store.js +99 -46
- package/dist/core/storage/pg-fact-store.js.map +1 -1
- package/dist/core/storage/pg-learner-store.d.ts +27 -0
- package/dist/core/storage/pg-learner-store.js +174 -0
- package/dist/core/storage/pg-learner-store.js.map +1 -0
- package/dist/core/storage/pg-session-store.d.ts +24 -20
- package/dist/core/storage/pg-session-store.js +162 -90
- package/dist/core/storage/pg-session-store.js.map +1 -1
- package/dist/core/storage/pg-signal-store.d.ts +10 -5
- package/dist/core/storage/pg-signal-store.js +24 -12
- package/dist/core/storage/pg-signal-store.js.map +1 -1
- package/dist/core/storage/pg-storage.d.ts +4 -0
- package/dist/core/storage/pg-storage.js +6 -0
- package/dist/core/storage/pg-storage.js.map +1 -1
- package/dist/core/storage/pg-workstream-store.d.ts +16 -11
- package/dist/core/storage/pg-workstream-store.js +46 -29
- package/dist/core/storage/pg-workstream-store.js.map +1 -1
- package/dist/core/storage/sqlite-code-exemplar-store.d.ts +24 -10
- package/dist/core/storage/sqlite-code-exemplar-store.js +84 -40
- package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/sqlite-entity-store.d.ts +8 -1
- package/dist/core/storage/sqlite-entity-store.js +46 -27
- package/dist/core/storage/sqlite-entity-store.js.map +1 -1
- package/dist/core/storage/sqlite-fact-store.d.ts +45 -19
- package/dist/core/storage/sqlite-fact-store.js +172 -64
- package/dist/core/storage/sqlite-fact-store.js.map +1 -1
- package/dist/core/storage/sqlite-learner-store.d.ts +33 -0
- package/dist/core/storage/sqlite-learner-store.js +178 -0
- package/dist/core/storage/sqlite-learner-store.js.map +1 -0
- package/dist/core/storage/sqlite-outcome-store.d.ts +37 -22
- package/dist/core/storage/sqlite-outcome-store.js +90 -37
- package/dist/core/storage/sqlite-outcome-store.js.map +1 -1
- package/dist/core/storage/sqlite-session-store.d.ts +29 -20
- package/dist/core/storage/sqlite-session-store.js +207 -121
- package/dist/core/storage/sqlite-session-store.js.map +1 -1
- package/dist/core/storage/sqlite-signal-store.d.ts +12 -5
- package/dist/core/storage/sqlite-signal-store.js +27 -15
- package/dist/core/storage/sqlite-signal-store.js.map +1 -1
- package/dist/core/storage/sqlite-storage.d.ts +4 -0
- package/dist/core/storage/sqlite-storage.js +10 -2
- package/dist/core/storage/sqlite-storage.js.map +1 -1
- package/dist/core/storage/sqlite-workstream-store.d.ts +16 -11
- package/dist/core/storage/sqlite-workstream-store.js +52 -31
- package/dist/core/storage/sqlite-workstream-store.js.map +1 -1
- package/dist/core/storage/supersedence-log.d.ts +10 -7
- package/dist/core/storage/supersedence-log.js +19 -14
- package/dist/core/storage/supersedence-log.js.map +1 -1
- package/dist/core/tenancy/default-team.d.ts +6 -0
- package/dist/core/tenancy/default-team.js +7 -0
- package/dist/core/tenancy/default-team.js.map +1 -0
- package/dist/core/tenancy/hosted-mode.d.ts +9 -0
- package/dist/core/tenancy/hosted-mode.js +12 -0
- package/dist/core/tenancy/hosted-mode.js.map +1 -0
- package/dist/core/tenancy/team-auth.d.ts +16 -0
- package/dist/core/tenancy/team-auth.js +22 -0
- package/dist/core/tenancy/team-auth.js.map +1 -0
- package/dist/core/tenancy/team-token-store.d.ts +45 -0
- package/dist/core/tenancy/team-token-store.js +52 -0
- package/dist/core/tenancy/team-token-store.js.map +1 -0
- package/dist/core/tenancy/tenant-clause.d.ts +37 -0
- package/dist/core/tenancy/tenant-clause.js +11 -0
- package/dist/core/tenancy/tenant-clause.js.map +1 -0
- package/dist/core/tenancy/tenant-state-path.d.ts +28 -0
- package/dist/core/tenancy/tenant-state-path.js +49 -0
- package/dist/core/tenancy/tenant-state-path.js.map +1 -0
- package/dist/core/wiki/project.d.ts +17 -0
- package/dist/core/wiki/project.js +37 -0
- package/dist/core/wiki/project.js.map +1 -0
- package/dist/core/wiki/reconcile.d.ts +15 -0
- package/dist/core/wiki/reconcile.js +14 -0
- package/dist/core/wiki/reconcile.js.map +1 -0
- package/dist/core/wiki/render.d.ts +5 -0
- package/dist/core/wiki/render.js +84 -0
- package/dist/core/wiki/render.js.map +1 -0
- package/dist/core/wiki/rollup.d.ts +28 -0
- package/dist/core/wiki/rollup.js +91 -0
- package/dist/core/wiki/rollup.js.map +1 -0
- package/dist/core/wiki/select.d.ts +8 -0
- package/dist/core/wiki/select.js +7 -0
- package/dist/core/wiki/select.js.map +1 -0
- package/dist/core/wiki/slug.d.ts +36 -0
- package/dist/core/wiki/slug.js +71 -0
- package/dist/core/wiki/slug.js.map +1 -0
- package/dist/core/wiki/types.d.ts +37 -0
- package/dist/core/wiki/types.js +2 -0
- package/dist/core/wiki/types.js.map +1 -0
- package/dist/core/work-digest/build-work-digest.d.ts +1 -1
- package/dist/core/work-digest/build-work-digest.js +3 -3
- package/dist/core/work-digest/build-work-digest.js.map +1 -1
- package/dist/core/workstream/bind.d.ts +1 -1
- package/dist/core/workstream/bind.js +10 -10
- package/dist/core/workstream/bind.js.map +1 -1
- package/dist/core/workstream/rollup.d.ts +1 -1
- package/dist/core/workstream/rollup.js +6 -6
- package/dist/core/workstream/rollup.js.map +1 -1
- package/dist/hook/hook-helpers.d.ts +14 -0
- package/dist/hook/hook-helpers.js +29 -2
- package/dist/hook/hook-helpers.js.map +1 -1
- package/dist/hook/pre-compact-hook.js +6 -4
- package/dist/hook/pre-compact-hook.js.map +1 -1
- package/dist/hook/prompt-recall-hook.d.ts +5 -2
- package/dist/hook/prompt-recall-hook.js +28 -17
- package/dist/hook/prompt-recall-hook.js.map +1 -1
- package/dist/hook/recall-over-http.d.ts +27 -3
- package/dist/hook/recall-over-http.js +44 -11
- package/dist/hook/recall-over-http.js.map +1 -1
- package/dist/hook/session-end-hook.js +7 -5
- package/dist/hook/session-end-hook.js.map +1 -1
- package/dist/hook/session-start-hook.d.ts +14 -1
- package/dist/hook/session-start-hook.js +55 -15
- package/dist/hook/session-start-hook.js.map +1 -1
- package/dist/hook/stop-hook.js +9 -7
- package/dist/hook/stop-hook.js.map +1 -1
- package/dist/http/app.d.ts +41 -3
- package/dist/http/app.js +355 -96
- package/dist/http/app.js.map +1 -1
- package/dist/install/claude-code.d.ts +17 -0
- package/dist/install/claude-code.js +44 -5
- package/dist/install/claude-code.js.map +1 -1
- package/dist/install/codex.d.ts +23 -2
- package/dist/install/codex.js +111 -14
- package/dist/install/codex.js.map +1 -1
- package/dist/install/cursor.d.ts +2 -2
- package/dist/install/cursor.js +7 -7
- package/dist/install/cursor.js.map +1 -1
- package/dist/install/hermes.d.ts +8 -0
- package/dist/install/hermes.js +28 -5
- package/dist/install/hermes.js.map +1 -1
- package/dist/install/local-source.d.ts +20 -0
- package/dist/install/local-source.js +28 -0
- package/dist/install/local-source.js.map +1 -0
- package/dist/install/mcp-block.d.ts +77 -0
- package/dist/install/mcp-block.js +99 -0
- package/dist/install/mcp-block.js.map +1 -0
- package/dist/install/pi.d.ts +26 -0
- package/dist/install/pi.js +43 -0
- package/dist/install/pi.js.map +1 -1
- package/dist/install/setup.js +6 -0
- package/dist/install/setup.js.map +1 -1
- package/dist/install/windsurf.d.ts +2 -2
- package/dist/install/windsurf.js +7 -7
- package/dist/install/windsurf.js.map +1 -1
- package/dist/llm/classifier-box.d.ts +5 -0
- package/dist/llm/classifier-box.js +5 -0
- package/dist/llm/classifier-box.js.map +1 -1
- package/dist/mcp/server.d.ts +73 -16
- package/dist/mcp/server.js +306 -83
- package/dist/mcp/server.js.map +1 -1
- package/dist/ports/clock.d.ts +12 -0
- package/dist/ports/clock.js +10 -0
- package/dist/ports/clock.js.map +1 -0
- package/dist/ports/code-exemplar-store.d.ts +13 -13
- package/dist/ports/entity-store.d.ts +5 -1
- package/dist/ports/fact-store.d.ts +0 -0
- package/dist/ports/fact-store.js +0 -0
- package/dist/ports/fact-store.js.map +1 -1
- package/dist/ports/learner-store.d.ts +80 -0
- package/dist/ports/learner-store.js +19 -0
- package/dist/ports/learner-store.js.map +1 -0
- package/dist/ports/outcome.d.ts +3 -3
- package/dist/ports/session-store.d.ts +20 -14
- package/dist/ports/session-store.js +5 -0
- package/dist/ports/session-store.js.map +1 -1
- package/dist/ports/signal-store.d.ts +12 -8
- package/dist/ports/spawn-child.d.ts +14 -0
- package/dist/ports/spawn-child.js +10 -0
- package/dist/ports/spawn-child.js.map +1 -0
- package/dist/ports/storage.d.ts +6 -0
- package/dist/ports/transcript-adapter.d.ts +11 -0
- package/dist/ports/wiki-writer.d.ts +19 -0
- package/dist/ports/wiki-writer.js +12 -0
- package/dist/ports/wiki-writer.js.map +1 -0
- package/dist/ports/workstream-store.d.ts +19 -12
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js.map +1 -1
- package/dist/shared/version.d.ts +9 -0
- package/dist/shared/version.js +11 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/ui/assets/index-D6F3xAis.js +11 -0
- package/dist/ui/index.html +1 -1
- package/migrations/033_actions_kind_check.sql +58 -0
- package/migrations/034_tenancy_teams_and_stamps.sql +40 -0
- package/migrations/035_tenancy_entity_rekey.sql +75 -0
- package/migrations/036_tenant_name_uniqueness.sql +59 -0
- package/migrations/037_sessions_covering_index.sql +25 -0
- package/migrations/038_sources_muse.sql +33 -0
- package/migrations/039_learner_evidence.sql +51 -0
- package/migrations/pg/033_actions_kind_check.sql +17 -0
- package/migrations/pg/034_tenancy.sql +77 -0
- package/migrations/pg/035_tenant_name_uniqueness.sql +15 -0
- package/migrations/pg/036_sources_muse.sql +12 -0
- package/migrations/pg/037_learner_evidence.sql +55 -0
- package/nlm/index.js +246 -55
- package/package.json +10 -5
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/scripts/prompt-recall-hook.mjs +244 -55
- package/plugin/scripts/session-start-hook.mjs +273 -53
- package/plugin/scripts/stop-hook.mjs +195 -37
- package/dist/ui/assets/index-CSaBtgXD.js +0 -11
|
@@ -9,15 +9,21 @@
|
|
|
9
9
|
* Embeddings live in code_exemplar_embeddings with ON DELETE CASCADE, so the
|
|
10
10
|
* prune/cap deletes here don't need separate vec bookkeeping (unlike the
|
|
11
11
|
* SQLite store, which deletes from code_exemplars_vec explicitly).
|
|
12
|
+
*
|
|
13
|
+
* Tenancy: mirrors SqliteCodeExemplarStore — every method takes `tenantId`
|
|
14
|
+
* as its non-optional first parameter and routes STAMP-table WHERE
|
|
15
|
+
* fragments through `tenantClausePg`. See that file's header comment for
|
|
16
|
+
* the vector-path rationale.
|
|
12
17
|
*/
|
|
13
18
|
import { exemplarId } from "./sqlite-code-exemplar-store.js";
|
|
19
|
+
import { tenantClausePg } from "../tenancy/tenant-clause.js";
|
|
14
20
|
const VEC_DIM = 768;
|
|
15
21
|
// Read column list stays scope-free while stamping is write-only (#348
|
|
16
22
|
// Stage A); reads gain scope in the enforcement task.
|
|
17
23
|
const COLUMNS = "id, install_scope, signal_id, session_id, repo, model, lang, " +
|
|
18
24
|
"task_context, code, code_hash, outcome, git_sha, survived, ts, created_at, " +
|
|
19
25
|
"retired_at, label_source";
|
|
20
|
-
function insertParams(input) {
|
|
26
|
+
function insertParams(input, tenantId) {
|
|
21
27
|
const id = exemplarId({
|
|
22
28
|
installScope: input.installScope,
|
|
23
29
|
repo: input.repo,
|
|
@@ -40,13 +46,14 @@ function insertParams(input) {
|
|
|
40
46
|
input.survived,
|
|
41
47
|
input.scope,
|
|
42
48
|
input.ts,
|
|
49
|
+
tenantId,
|
|
43
50
|
];
|
|
44
51
|
}
|
|
45
52
|
const INSERT_SQL = `
|
|
46
53
|
INSERT INTO code_exemplars
|
|
47
54
|
(id, install_scope, signal_id, session_id, repo, model, lang,
|
|
48
|
-
task_context, code, code_hash, outcome, git_sha, survived, scope, ts)
|
|
49
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
|
55
|
+
task_context, code, code_hash, outcome, git_sha, survived, scope, ts, tenant_id)
|
|
56
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
|
50
57
|
ON CONFLICT (id) DO NOTHING
|
|
51
58
|
`;
|
|
52
59
|
export class PgCodeExemplarStore {
|
|
@@ -54,12 +61,12 @@ export class PgCodeExemplarStore {
|
|
|
54
61
|
constructor(pool) {
|
|
55
62
|
this.pool = pool;
|
|
56
63
|
}
|
|
57
|
-
async insert(input) {
|
|
58
|
-
const params = insertParams(input);
|
|
64
|
+
async insert(tenantId, input) {
|
|
65
|
+
const params = insertParams(input, tenantId);
|
|
59
66
|
const res = await this.pool.query(INSERT_SQL, params);
|
|
60
67
|
return { id: params[0], skipped: res.rowCount === 0 };
|
|
61
68
|
}
|
|
62
|
-
async insertMany(inputs) {
|
|
69
|
+
async insertMany(tenantId, inputs) {
|
|
63
70
|
if (inputs.length === 0)
|
|
64
71
|
return 0;
|
|
65
72
|
const client = await this.pool.connect();
|
|
@@ -67,7 +74,7 @@ export class PgCodeExemplarStore {
|
|
|
67
74
|
try {
|
|
68
75
|
await client.query("BEGIN");
|
|
69
76
|
for (const input of inputs) {
|
|
70
|
-
const res = await client.query(INSERT_SQL, insertParams(input));
|
|
77
|
+
const res = await client.query(INSERT_SQL, insertParams(input, tenantId));
|
|
71
78
|
if (res.rowCount && res.rowCount > 0)
|
|
72
79
|
inserted++;
|
|
73
80
|
}
|
|
@@ -82,30 +89,46 @@ export class PgCodeExemplarStore {
|
|
|
82
89
|
}
|
|
83
90
|
return inserted;
|
|
84
91
|
}
|
|
85
|
-
|
|
92
|
+
/**
|
|
93
|
+
* No-op if exemplarId isn't owned by tenantId — writing an embedding for
|
|
94
|
+
* another tenant's exemplar must never fall through to a write.
|
|
95
|
+
*/
|
|
96
|
+
async upsertEmbedding(tenantId, exemplarId, vector) {
|
|
86
97
|
if (vector.length !== VEC_DIM) {
|
|
87
98
|
throw new Error(`code exemplar embeddings must be ${VEC_DIM}-dim (got ${vector.length})`);
|
|
88
99
|
}
|
|
100
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
101
|
+
const owned = await this.pool.query(`SELECT id FROM code_exemplars WHERE id = $1 AND ${tc.sql}`, [exemplarId, tc.param]);
|
|
102
|
+
if (owned.rows.length === 0)
|
|
103
|
+
return;
|
|
89
104
|
const vecStr = `[${Array.from(vector).join(",")}]`;
|
|
90
105
|
await this.pool.query(`INSERT INTO code_exemplar_embeddings (exemplar_id, embedding)
|
|
91
106
|
VALUES ($1, $2::vector)
|
|
92
107
|
ON CONFLICT (exemplar_id) DO UPDATE SET embedding = EXCLUDED.embedding`, [exemplarId, vecStr]);
|
|
93
108
|
}
|
|
94
|
-
async searchByVector(queryVector, filter) {
|
|
109
|
+
async searchByVector(tenantId, queryVector, filter) {
|
|
95
110
|
const k = Math.max(1, Math.min(50, filter.k ?? 5));
|
|
96
111
|
const includeNegatives = filter.includeNegatives ?? true;
|
|
97
112
|
const overFetch = k * 4;
|
|
98
113
|
const vecStr = `[${Array.from(queryVector).join(",")}]`;
|
|
99
114
|
// pgvector <-> is L2 distance; OllamaCodeEmbedder L2-normalises vectors,
|
|
100
115
|
// so this orders identically to cosine and matches the SQLite vec0 lane.
|
|
101
|
-
|
|
116
|
+
// Tenant filter applied in the id-resolution join against code_exemplars
|
|
117
|
+
// (program spec §4.3 vector-path rule) — code_exemplar_embeddings
|
|
118
|
+
// carries no tenant_id of its own.
|
|
119
|
+
const tc = tenantClausePg(tenantId, 3);
|
|
120
|
+
const res = await this.pool.query(`SELECT ${COLUMNS.split(", ").map((c) => `ce.${c}`).join(", ")}, ce.tenant_id,
|
|
102
121
|
e.embedding <-> $1::vector AS distance
|
|
103
122
|
FROM code_exemplar_embeddings e
|
|
104
123
|
JOIN code_exemplars ce ON ce.id = e.exemplar_id
|
|
105
|
-
WHERE ce.install_scope = $2 AND ce.retired_at IS NULL
|
|
124
|
+
WHERE ce.install_scope = $2 AND ce.retired_at IS NULL AND ${tc.sql}
|
|
106
125
|
ORDER BY e.embedding <-> $1::vector
|
|
107
|
-
LIMIT $
|
|
108
|
-
|
|
126
|
+
LIMIT $4`, [vecStr, filter.installScope, tc.param, overFetch]);
|
|
127
|
+
// Defense in depth (never a substitute for the SQL filter above): re-check
|
|
128
|
+
// each resolved row's own tenant, read into a local first so this JS
|
|
129
|
+
// comparison can never be mistaken by the tenant-guard scan for an
|
|
130
|
+
// inlined SQL WHERE fragment (that literal is reserved for tenant-clause.ts).
|
|
131
|
+
let hits = res.rows.filter((r) => { const rowTenant = r["tenant_id"]; return rowTenant === tenantId; }).map((r) => ({
|
|
109
132
|
id: r.id,
|
|
110
133
|
code: r.code,
|
|
111
134
|
taskContext: r.task_context,
|
|
@@ -135,21 +158,24 @@ export class PgCodeExemplarStore {
|
|
|
135
158
|
});
|
|
136
159
|
return hits.slice(0, k);
|
|
137
160
|
}
|
|
138
|
-
async getById(id) {
|
|
139
|
-
const
|
|
161
|
+
async getById(tenantId, id) {
|
|
162
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
163
|
+
const res = await this.pool.query(`SELECT ${COLUMNS} FROM code_exemplars WHERE id = $1 AND ${tc.sql}`, [id, tc.param]);
|
|
140
164
|
const row = res.rows[0];
|
|
141
165
|
return row ? this.rowToExemplar(row) : null;
|
|
142
166
|
}
|
|
143
|
-
async listBySessions(sessionIds) {
|
|
167
|
+
async listBySessions(tenantId, sessionIds) {
|
|
144
168
|
if (sessionIds.length === 0)
|
|
145
169
|
return [];
|
|
146
170
|
const ph = sessionIds.map((_, i) => `$${i + 1}`).join(",");
|
|
147
|
-
const
|
|
171
|
+
const tc = tenantClausePg(tenantId, sessionIds.length + 1);
|
|
172
|
+
const res = await this.pool.query(`SELECT ${COLUMNS} FROM code_exemplars WHERE session_id IN (${ph}) AND retired_at IS NULL AND ${tc.sql} ORDER BY ts ASC`, [...sessionIds, tc.param]);
|
|
148
173
|
return res.rows.map((r) => this.rowToExemplar(r));
|
|
149
174
|
}
|
|
150
|
-
async applyBucketCap(installScope, maxPerBucket) {
|
|
175
|
+
async applyBucketCap(tenantId, installScope, maxPerBucket) {
|
|
151
176
|
// Window-rank within each (repo, lang, outcome-class) bucket newest-first,
|
|
152
177
|
// delete everything past the cap. Cascade clears the embeddings.
|
|
178
|
+
const tc = tenantClausePg(tenantId, 3);
|
|
153
179
|
const res = await this.pool.query(`WITH ranked AS (
|
|
154
180
|
SELECT id, ROW_NUMBER() OVER (
|
|
155
181
|
PARTITION BY repo, lang,
|
|
@@ -157,18 +183,20 @@ export class PgCodeExemplarStore {
|
|
|
157
183
|
ORDER BY ts DESC
|
|
158
184
|
) AS rn
|
|
159
185
|
FROM code_exemplars
|
|
160
|
-
WHERE install_scope = $1
|
|
186
|
+
WHERE install_scope = $1 AND ${tc.sql}
|
|
161
187
|
)
|
|
162
188
|
DELETE FROM code_exemplars
|
|
163
|
-
WHERE id IN (SELECT id FROM ranked WHERE rn > $2)`, [installScope, maxPerBucket]);
|
|
189
|
+
WHERE id IN (SELECT id FROM ranked WHERE rn > $2)`, [installScope, maxPerBucket, tc.param]);
|
|
164
190
|
return res.rowCount ?? 0;
|
|
165
191
|
}
|
|
166
|
-
async pruneReverted(installScope) {
|
|
167
|
-
const
|
|
192
|
+
async pruneReverted(tenantId, installScope) {
|
|
193
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
194
|
+
const res = await this.pool.query(`DELETE FROM code_exemplars WHERE install_scope = $1 AND survived = 0 AND ${tc.sql}`, [installScope, tc.param]);
|
|
168
195
|
return res.rowCount ?? 0;
|
|
169
196
|
}
|
|
170
|
-
async setVerdict(id, patch, source) {
|
|
171
|
-
const
|
|
197
|
+
async setVerdict(tenantId, id, patch, source) {
|
|
198
|
+
const curTc = tenantClausePg(tenantId, 2);
|
|
199
|
+
const cur = await this.pool.query(`SELECT label_source FROM code_exemplars WHERE id = $1 AND ${curTc.sql}`, [id, curTc.param]);
|
|
172
200
|
if (cur.rows.length === 0)
|
|
173
201
|
return { status: "not_found" };
|
|
174
202
|
if (source === "llm" && cur.rows[0].label_source === "human")
|
|
@@ -187,11 +215,14 @@ export class PgCodeExemplarStore {
|
|
|
187
215
|
values.push(patch.outcome);
|
|
188
216
|
}
|
|
189
217
|
values.push(id);
|
|
190
|
-
|
|
218
|
+
const updateTc = tenantClausePg(tenantId, n + 1);
|
|
219
|
+
values.push(updateTc.param);
|
|
220
|
+
await this.pool.query(`UPDATE code_exemplars SET ${sets.join(", ")} WHERE id = $${n} AND ${updateTc.sql}`, values);
|
|
191
221
|
return { status: "applied" };
|
|
192
222
|
}
|
|
193
|
-
async pruneOlderThan(olderThanTs) {
|
|
194
|
-
const
|
|
223
|
+
async pruneOlderThan(tenantId, olderThanTs) {
|
|
224
|
+
const tc = tenantClausePg(tenantId, 2);
|
|
225
|
+
const res = await this.pool.query(`DELETE FROM code_exemplars WHERE ts < $1 AND ${tc.sql}`, [olderThanTs, tc.param]);
|
|
195
226
|
return res.rowCount ?? 0;
|
|
196
227
|
}
|
|
197
228
|
rowToExemplar(row) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-code-exemplar-store.js","sourceRoot":"","sources":["../../../src/core/storage/pg-code-exemplar-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pg-code-exemplar-store.js","sourceRoot":"","sources":["../../../src/core/storage/pg-code-exemplar-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* PgEntityStore -- EntityStore implementation over pg.Pool.
|
|
3
3
|
*
|
|
4
4
|
* All merge operations run inside a single pg transaction.
|
|
5
|
+
*
|
|
6
|
+
* Tenancy: mirrors SqliteEntityStore — merge takes tenantId as its
|
|
7
|
+
* non-optional first parameter and routes every STAMP-table WHERE fragment
|
|
8
|
+
* through tenantClausePg. entities/entity_variants carry a composite PK
|
|
9
|
+
* (tenant_id, canonical/variant).
|
|
5
10
|
*/
|
|
6
11
|
import type { Pool } from "pg";
|
|
7
12
|
import type { EntityStore } from "../../ports/entity-store.js";
|
|
8
13
|
export declare class PgEntityStore implements EntityStore {
|
|
9
14
|
private readonly pool;
|
|
10
15
|
constructor(pool: Pool);
|
|
11
|
-
merge(source: string, target: string): Promise<void>;
|
|
16
|
+
merge(tenantId: string, source: string, target: string): Promise<void>;
|
|
12
17
|
}
|
|
@@ -2,69 +2,84 @@
|
|
|
2
2
|
* PgEntityStore -- EntityStore implementation over pg.Pool.
|
|
3
3
|
*
|
|
4
4
|
* All merge operations run inside a single pg transaction.
|
|
5
|
+
*
|
|
6
|
+
* Tenancy: mirrors SqliteEntityStore — merge takes tenantId as its
|
|
7
|
+
* non-optional first parameter and routes every STAMP-table WHERE fragment
|
|
8
|
+
* through tenantClausePg. entities/entity_variants carry a composite PK
|
|
9
|
+
* (tenant_id, canonical/variant).
|
|
5
10
|
*/
|
|
11
|
+
import { tenantClausePg } from "../tenancy/tenant-clause.js";
|
|
6
12
|
export class PgEntityStore {
|
|
7
13
|
pool;
|
|
8
14
|
constructor(pool) {
|
|
9
15
|
this.pool = pool;
|
|
10
16
|
}
|
|
11
|
-
async merge(source, target) {
|
|
17
|
+
async merge(tenantId, source, target) {
|
|
12
18
|
const client = await this.pool.connect();
|
|
13
19
|
try {
|
|
14
20
|
await client.query("BEGIN");
|
|
15
|
-
const
|
|
21
|
+
const targetTc = tenantClausePg(tenantId, 2);
|
|
22
|
+
const targetRes = await client.query(`SELECT status FROM entities WHERE canonical = $1 AND ${targetTc.sql}`, [target, targetTc.param]);
|
|
16
23
|
if (targetRes.rowCount === 0) {
|
|
17
24
|
throw new Error(`merge: target entity not found: ${target}`);
|
|
18
25
|
}
|
|
19
26
|
if (targetRes.rows[0].status === "retired") {
|
|
20
27
|
throw new Error(`merge: target entity is retired: ${target}`);
|
|
21
28
|
}
|
|
22
|
-
const
|
|
29
|
+
const sourceTc = tenantClausePg(tenantId, 2);
|
|
30
|
+
const sourceRes = await client.query(`SELECT status FROM entities WHERE canonical = $1 AND ${sourceTc.sql}`, [source, sourceTc.param]);
|
|
23
31
|
if (sourceRes.rowCount === 0) {
|
|
24
32
|
throw new Error(`merge: source entity not found: ${source}`);
|
|
25
33
|
}
|
|
26
34
|
// Step 1: copy source session_entities to target, dedup on composite PK.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
const copyTc = tenantClausePg(tenantId, 3);
|
|
36
|
+
await client.query(`INSERT INTO session_entities (tenant_id, session_id, entity_canonical)
|
|
37
|
+
SELECT $3, session_id, $1 FROM session_entities WHERE entity_canonical = $2 AND ${copyTc.sql}
|
|
38
|
+
ON CONFLICT DO NOTHING`, [target, source, copyTc.param]);
|
|
30
39
|
// Step 2: delete source's session_entities rows.
|
|
31
|
-
|
|
40
|
+
const deleteEntTc = tenantClausePg(tenantId, 2);
|
|
41
|
+
await client.query(`DELETE FROM session_entities WHERE entity_canonical = $1 AND ${deleteEntTc.sql}`, [source, deleteEntTc.param]);
|
|
32
42
|
// Step 3: recompute target.session_count exactly from session_entities.
|
|
43
|
+
const countTc = tenantClausePg(tenantId, 2);
|
|
33
44
|
await client.query(`UPDATE entities
|
|
34
|
-
SET session_count = (SELECT COUNT(*) FROM session_entities WHERE entity_canonical = $1),
|
|
45
|
+
SET session_count = (SELECT COUNT(*) FROM session_entities WHERE entity_canonical = $1 AND ${countTc.sql}),
|
|
35
46
|
updated_at = NOW()
|
|
36
|
-
WHERE canonical = $1`, [target]);
|
|
47
|
+
WHERE canonical = $1 AND ${countTc.sql}`, [target, countTc.param]);
|
|
37
48
|
// Step 4: widen first_seen_session / last_seen_session.
|
|
38
49
|
// first_seen and last_seen are session IDs (text FK to sessions.id).
|
|
39
50
|
// Join to sessions to order by started_at and pick earliest / latest.
|
|
51
|
+
const seenTc = tenantClausePg(tenantId, 2);
|
|
40
52
|
const seenRes = await client.query(`SELECT id, started_at FROM sessions
|
|
41
53
|
WHERE id IN (
|
|
42
|
-
SELECT first_seen_session FROM entities WHERE canonical = ANY($1)
|
|
54
|
+
SELECT first_seen_session FROM entities WHERE canonical = ANY($1) AND ${seenTc.sql}
|
|
43
55
|
UNION
|
|
44
|
-
SELECT last_seen_session FROM entities WHERE canonical = ANY($1)
|
|
45
|
-
)`, [[source, target]]);
|
|
56
|
+
SELECT last_seen_session FROM entities WHERE canonical = ANY($1) AND ${seenTc.sql}
|
|
57
|
+
)`, [[source, target], seenTc.param]);
|
|
46
58
|
if (seenRes.rows.length > 0) {
|
|
47
59
|
const sorted = seenRes.rows.slice().sort((a, b) => a.started_at.localeCompare(b.started_at));
|
|
48
60
|
const earliest = sorted[0].id;
|
|
49
61
|
const latest = sorted[sorted.length - 1].id;
|
|
62
|
+
const widenTc = tenantClausePg(tenantId, 4);
|
|
50
63
|
await client.query(`UPDATE entities
|
|
51
64
|
SET first_seen_session = $1,
|
|
52
65
|
last_seen_session = $2,
|
|
53
66
|
updated_at = NOW()
|
|
54
|
-
WHERE canonical = $3`, [earliest, latest, target]);
|
|
67
|
+
WHERE canonical = $3 AND ${widenTc.sql}`, [earliest, latest, target, widenTc.param]);
|
|
55
68
|
}
|
|
56
69
|
// Step 5: insert the variant record so future ingest resolves source -> target.
|
|
57
|
-
await client.query(`INSERT INTO entity_variants (variant, canonical, source_session_id)
|
|
58
|
-
VALUES ($1, $2, NULL)
|
|
59
|
-
ON CONFLICT DO NOTHING`, [source, target]);
|
|
70
|
+
await client.query(`INSERT INTO entity_variants (tenant_id, variant, canonical, source_session_id)
|
|
71
|
+
VALUES ($1, $2, $3, NULL)
|
|
72
|
+
ON CONFLICT DO NOTHING`, [tenantId, source, target]);
|
|
60
73
|
// Step 6: re-point existing variants of source to target.
|
|
61
|
-
|
|
74
|
+
const repointTc = tenantClausePg(tenantId, 3);
|
|
75
|
+
await client.query(`UPDATE entity_variants SET canonical = $1 WHERE canonical = $2 AND variant != $2 AND ${repointTc.sql}`, [target, source, repointTc.param]);
|
|
62
76
|
// Step 7: retire the source entity row in place.
|
|
77
|
+
const retireTc = tenantClausePg(tenantId, 2);
|
|
63
78
|
await client.query(`UPDATE entities
|
|
64
79
|
SET status = 'retired',
|
|
65
80
|
session_count = 0,
|
|
66
81
|
updated_at = NOW()
|
|
67
|
-
WHERE canonical = $1`, [source]);
|
|
82
|
+
WHERE canonical = $1 AND ${retireTc.sql}`, [source, retireTc.param]);
|
|
68
83
|
await client.query("COMMIT");
|
|
69
84
|
}
|
|
70
85
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-entity-store.js","sourceRoot":"","sources":["../../../src/core/storage/pg-entity-store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pg-entity-store.js","sourceRoot":"","sources":["../../../src/core/storage/pg-entity-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { PoolClient } from "pg";
|
|
14
14
|
import type { Fact } from "../../shared/types.js";
|
|
15
|
-
export declare function ingestSessionFactsOnClient(client: PoolClient, sessionId: string, facts: ReadonlyArray<Fact>, scope?: string | null): Promise<void>;
|
|
15
|
+
export declare function ingestSessionFactsOnClient(client: PoolClient, tenantId: string, sessionId: string, facts: ReadonlyArray<Fact>, scope?: string | null): Promise<void>;
|
|
@@ -11,20 +11,23 @@
|
|
|
11
11
|
* - every fact the collapse supersedes leaves the ANN index immediately
|
|
12
12
|
*/
|
|
13
13
|
import { batchWinners } from "./fact-batch.js";
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
import { tenantClausePg } from "../tenancy/tenant-clause.js";
|
|
15
|
+
export async function ingestSessionFactsOnClient(client, tenantId, sessionId, facts, scope = null) {
|
|
16
|
+
const deleteTc = tenantClausePg(tenantId, 2);
|
|
17
|
+
await client.query(`DELETE FROM facts WHERE source_session_id = $1 AND ${deleteTc.sql}`, [sessionId, deleteTc.param]);
|
|
16
18
|
if (facts.length === 0)
|
|
17
19
|
return;
|
|
18
20
|
for (const f of facts) {
|
|
19
21
|
await client.query(`INSERT INTO facts (id, kind, subject, predicate, value, source_session_id,
|
|
20
|
-
source_quote, created_at, superseded_by, confidence, retired_at, scope)
|
|
21
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [f.id, f.kind, f.subject, f.predicate, f.value, f.sourceSessionId,
|
|
22
|
-
f.sourceQuote, f.createdAt, f.supersededBy, f.confidence, f.retiredAt, scope]);
|
|
22
|
+
source_quote, created_at, superseded_by, confidence, retired_at, scope, tenant_id)
|
|
23
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [f.id, f.kind, f.subject, f.predicate, f.value, f.sourceSessionId,
|
|
24
|
+
f.sourceQuote, f.createdAt, f.supersededBy, f.confidence, f.retiredAt, scope, tenantId]);
|
|
23
25
|
}
|
|
24
26
|
for (const f of batchWinners(facts)) {
|
|
27
|
+
const collapseTc = tenantClausePg(tenantId, 4);
|
|
25
28
|
const collapsed = await client.query(`UPDATE facts SET superseded_by = $1
|
|
26
|
-
WHERE subject = $2 AND predicate = $3 AND superseded_by IS NULL AND id != $1
|
|
27
|
-
RETURNING id`, [f.id, f.subject, f.predicate]);
|
|
29
|
+
WHERE subject = $2 AND predicate = $3 AND superseded_by IS NULL AND id != $1 AND ${collapseTc.sql}
|
|
30
|
+
RETURNING id`, [f.id, f.subject, f.predicate, collapseTc.param]);
|
|
28
31
|
const ids = collapsed.rows.map((r) => r.id);
|
|
29
32
|
if (ids.length > 0) {
|
|
30
33
|
await client.query("DELETE FROM fact_embeddings WHERE fact_id = ANY($1)", [ids]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-fact-ingest.js","sourceRoot":"","sources":["../../../src/core/storage/pg-fact-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"pg-fact-ingest.js","sourceRoot":"","sources":["../../../src/core/storage/pg-fact-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAkB,EAClB,QAAgB,EAChB,SAAiB,EACjB,KAA0B,EAC1B,QAAuB,IAAI;IAE3B,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,CAAC,KAAK,CAAC,sDAAsD,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACtH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE/B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,MAAM,CAAC,KAAK,CAChB;;uEAEiE,EACjE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,eAAe;YAChE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CACzF,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,KAAK,CAClC;0FACoF,UAAU,CAAC,GAAG;oBACpF,EACd,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,CACjD,CAAC;QACF,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -2,33 +2,45 @@
|
|
|
2
2
|
* PgFactStore — FactStore implementation over pg.Pool + pgvector.
|
|
3
3
|
*
|
|
4
4
|
* Receives its Pool from PgStorage. Never opens its own connection.
|
|
5
|
+
*
|
|
6
|
+
* Tenancy: mirrors SqliteFactStore — every method takes `tenantId` as its
|
|
7
|
+
* non-optional first parameter and routes STAMP-table WHERE fragments
|
|
8
|
+
* through `tenantClausePg`. See that file's header comment for the full
|
|
9
|
+
* per-table rationale, including the vector-path re-resolution in
|
|
10
|
+
* semanticSearch.
|
|
5
11
|
*/
|
|
6
12
|
import type { Pool } from "pg";
|
|
7
|
-
import type { FactListFilter, FactQuery, FactSemanticNeighbor, FactStore } from "../../ports/fact-store.js";
|
|
13
|
+
import type { FactListFilter, FactQuery, FactSemanticNeighbor, FactStore, SubjectStat } from "../../ports/fact-store.js";
|
|
8
14
|
import type { Fact, FactHistoryChain } from "../../shared/types.js";
|
|
9
15
|
export declare class PgFactStore implements FactStore {
|
|
10
16
|
private readonly pool;
|
|
11
17
|
constructor(pool: Pool);
|
|
12
|
-
insert(fact: Fact): Promise<void>;
|
|
13
|
-
insertMany(facts: ReadonlyArray<Fact>): Promise<void>;
|
|
14
|
-
getById(id: string): Promise<Fact | null>;
|
|
15
|
-
getByIds(ids: ReadonlyArray<string>): Promise<ReadonlyArray<Fact>>;
|
|
16
|
-
findCurrent(subject: string, predicate: string): Promise<Fact | null>;
|
|
17
|
-
list(query: FactQuery): Promise<ReadonlyArray<Fact>>;
|
|
18
|
-
listBySession(sessionId: string): Promise<ReadonlyArray<Fact>>;
|
|
19
|
-
listBySessions(sessionIds: ReadonlyArray<string>, opts?: {
|
|
18
|
+
insert(tenantId: string, fact: Fact): Promise<void>;
|
|
19
|
+
insertMany(tenantId: string, facts: ReadonlyArray<Fact>): Promise<void>;
|
|
20
|
+
getById(tenantId: string, id: string): Promise<Fact | null>;
|
|
21
|
+
getByIds(tenantId: string, ids: ReadonlyArray<string>): Promise<ReadonlyArray<Fact>>;
|
|
22
|
+
findCurrent(tenantId: string, subject: string, predicate: string): Promise<Fact | null>;
|
|
23
|
+
list(tenantId: string, query: FactQuery): Promise<ReadonlyArray<Fact>>;
|
|
24
|
+
listBySession(tenantId: string, sessionId: string): Promise<ReadonlyArray<Fact>>;
|
|
25
|
+
listBySessions(tenantId: string, sessionIds: ReadonlyArray<string>, opts?: {
|
|
20
26
|
includeSuperseded?: boolean;
|
|
21
27
|
}): Promise<ReadonlyArray<Fact>>;
|
|
22
|
-
listForRecall(filter: FactListFilter): Promise<ReadonlyArray<Fact>>;
|
|
23
|
-
markSuperseded(oldId: string, newId: string | null): Promise<void>;
|
|
24
|
-
retire(factId: string): Promise<void>;
|
|
25
|
-
ingestSessionFacts(sessionId: string, facts: ReadonlyArray<Fact>): Promise<void>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
listForRecall(tenantId: string, filter: FactListFilter): Promise<ReadonlyArray<Fact>>;
|
|
29
|
+
markSuperseded(tenantId: string, oldId: string, newId: string | null): Promise<void>;
|
|
30
|
+
retire(tenantId: string, factId: string): Promise<void>;
|
|
31
|
+
ingestSessionFacts(tenantId: string, sessionId: string, facts: ReadonlyArray<Fact>): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Guarded by a tenant-scoped existence check — writing an embedding for a
|
|
34
|
+
* fact outside the caller's tenant is a no-op, not a fallthrough write.
|
|
35
|
+
*/
|
|
36
|
+
upsertEmbedding(tenantId: string, factId: string, vector: Float32Array): Promise<void>;
|
|
37
|
+
semanticSearch(tenantId: string, queryVector: Float32Array, limit: number): Promise<ReadonlyArray<FactSemanticNeighbor>>;
|
|
38
|
+
getHistory(tenantId: string, subject: string, predicate?: string): Promise<ReadonlyArray<FactHistoryChain>>;
|
|
39
|
+
corroborationCounts(tenantId: string, triples: ReadonlyArray<{
|
|
30
40
|
readonly subject: string;
|
|
31
41
|
readonly predicate: string;
|
|
32
42
|
readonly value: string;
|
|
33
43
|
}>): Promise<Map<string, number>>;
|
|
44
|
+
listSubjectStats(_tenantId: string): Promise<ReadonlyArray<SubjectStat>>;
|
|
45
|
+
listBySubjects(_tenantId: string, _subjects: ReadonlyArray<string>): Promise<ReadonlyArray<Fact>>;
|
|
34
46
|
}
|