@astragenie/astramemory-local 0.7.2
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/CHANGELOG.md +341 -0
- package/README.md +419 -0
- package/dist/backup/retention.d.ts +15 -0
- package/dist/backup/retention.js +62 -0
- package/dist/backup/retention.js.map +1 -0
- package/dist/backup/snapshot.d.ts +21 -0
- package/dist/backup/snapshot.js +55 -0
- package/dist/backup/snapshot.js.map +1 -0
- package/dist/backup/verify.d.ts +23 -0
- package/dist/backup/verify.js +77 -0
- package/dist/backup/verify.js.map +1 -0
- package/dist/budget/tracker.d.ts +58 -0
- package/dist/budget/tracker.js +102 -0
- package/dist/budget/tracker.js.map +1 -0
- package/dist/capture/codex.d.ts +63 -0
- package/dist/capture/codex.js +0 -0
- package/dist/capture/codex.js.map +1 -0
- package/dist/cli/backup.d.ts +1 -0
- package/dist/cli/backup.js +112 -0
- package/dist/cli/backup.js.map +1 -0
- package/dist/cli/budget.d.ts +7 -0
- package/dist/cli/budget.js +44 -0
- package/dist/cli/budget.js.map +1 -0
- package/dist/cli/capture.d.ts +10 -0
- package/dist/cli/capture.js +113 -0
- package/dist/cli/capture.js.map +1 -0
- package/dist/cli/consolidate.d.ts +16 -0
- package/dist/cli/consolidate.js +146 -0
- package/dist/cli/consolidate.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +54 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/entity-backfill.d.ts +10 -0
- package/dist/cli/entity-backfill.js +46 -0
- package/dist/cli/entity-backfill.js.map +1 -0
- package/dist/cli/hook-install.d.ts +45 -0
- package/dist/cli/hook-install.js +77 -0
- package/dist/cli/hook-install.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +312 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +431 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-stdio.d.ts +18 -0
- package/dist/cli/mcp-stdio.js +67 -0
- package/dist/cli/mcp-stdio.js.map +1 -0
- package/dist/cli/memory.d.ts +15 -0
- package/dist/cli/memory.js +52 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/open-runtime-db.d.ts +15 -0
- package/dist/cli/open-runtime-db.js +37 -0
- package/dist/cli/open-runtime-db.js.map +1 -0
- package/dist/cli/pair.d.ts +29 -0
- package/dist/cli/pair.js +64 -0
- package/dist/cli/pair.js.map +1 -0
- package/dist/cli/providers.d.ts +10 -0
- package/dist/cli/providers.js +97 -0
- package/dist/cli/providers.js.map +1 -0
- package/dist/cli/queue-purge.d.ts +5 -0
- package/dist/cli/queue-purge.js +92 -0
- package/dist/cli/queue-purge.js.map +1 -0
- package/dist/cli/queue.d.ts +29 -0
- package/dist/cli/queue.js +73 -0
- package/dist/cli/queue.js.map +1 -0
- package/dist/cli/rebuild.d.ts +15 -0
- package/dist/cli/rebuild.js +70 -0
- package/dist/cli/rebuild.js.map +1 -0
- package/dist/cli/reembed-dim.d.ts +21 -0
- package/dist/cli/reembed-dim.js +199 -0
- package/dist/cli/reembed-dim.js.map +1 -0
- package/dist/cli/reinstall.d.ts +1 -0
- package/dist/cli/reinstall.js +205 -0
- package/dist/cli/reinstall.js.map +1 -0
- package/dist/cli/restore.d.ts +1 -0
- package/dist/cli/restore.js +167 -0
- package/dist/cli/restore.js.map +1 -0
- package/dist/cli/retag.d.ts +14 -0
- package/dist/cli/retag.js +62 -0
- package/dist/cli/retag.js.map +1 -0
- package/dist/cli/search.d.ts +66 -0
- package/dist/cli/search.js +174 -0
- package/dist/cli/search.js.map +1 -0
- package/dist/cli/serve.d.ts +9 -0
- package/dist/cli/serve.js +364 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/service.d.ts +1 -0
- package/dist/cli/service.js +121 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/sync.d.ts +15 -0
- package/dist/cli/sync.js +61 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/token.d.ts +24 -0
- package/dist/cli/token.js +77 -0
- package/dist/cli/token.js.map +1 -0
- package/dist/cli/wait-health.d.ts +4 -0
- package/dist/cli/wait-health.js +23 -0
- package/dist/cli/wait-health.js.map +1 -0
- package/dist/config/config.d.ts +127 -0
- package/dist/config/config.js +38 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/datadir.d.ts +30 -0
- package/dist/config/datadir.js +65 -0
- package/dist/config/datadir.js.map +1 -0
- package/dist/config/loader.d.ts +23 -0
- package/dist/config/loader.js +102 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/migrate-dirs.d.ts +36 -0
- package/dist/config/migrate-dirs.js +132 -0
- package/dist/config/migrate-dirs.js.map +1 -0
- package/dist/config/persist-envs.d.ts +23 -0
- package/dist/config/persist-envs.js +119 -0
- package/dist/config/persist-envs.js.map +1 -0
- package/dist/config/resolve-runtime.d.ts +19 -0
- package/dist/config/resolve-runtime.js +53 -0
- package/dist/config/resolve-runtime.js.map +1 -0
- package/dist/config/secrets.d.ts +28 -0
- package/dist/config/secrets.js +38 -0
- package/dist/config/secrets.js.map +1 -0
- package/dist/config/sync-settings.d.ts +16 -0
- package/dist/config/sync-settings.js +34 -0
- package/dist/config/sync-settings.js.map +1 -0
- package/dist/config/writer.d.ts +19 -0
- package/dist/config/writer.js +121 -0
- package/dist/config/writer.js.map +1 -0
- package/dist/consolidate/consolidate.d.ts +80 -0
- package/dist/consolidate/consolidate.js +0 -0
- package/dist/consolidate/consolidate.js.map +1 -0
- package/dist/consolidate/proposals.d.ts +35 -0
- package/dist/consolidate/proposals.js +66 -0
- package/dist/consolidate/proposals.js.map +1 -0
- package/dist/contracts/atom-wire.d.ts +48 -0
- package/dist/contracts/atom-wire.js +55 -0
- package/dist/contracts/atom-wire.js.map +1 -0
- package/dist/contracts/embed.d.ts +41 -0
- package/dist/contracts/embed.js +20 -0
- package/dist/contracts/embed.js.map +1 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +6 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/job.d.ts +113 -0
- package/dist/contracts/job.js +32 -0
- package/dist/contracts/job.js.map +1 -0
- package/dist/contracts/llm.d.ts +30 -0
- package/dist/contracts/llm.js +2 -0
- package/dist/contracts/llm.js.map +1 -0
- package/dist/contracts/memory.d.ts +47 -0
- package/dist/contracts/memory.js +5 -0
- package/dist/contracts/memory.js.map +1 -0
- package/dist/contracts/vector.d.ts +29 -0
- package/dist/contracts/vector.js +2 -0
- package/dist/contracts/vector.js.map +1 -0
- package/dist/distill/flatten-turns.d.ts +1 -0
- package/dist/distill/flatten-turns.js +50 -0
- package/dist/distill/flatten-turns.js.map +1 -0
- package/dist/distill/pipeline.d.ts +45 -0
- package/dist/distill/pipeline.js +113 -0
- package/dist/distill/pipeline.js.map +1 -0
- package/dist/distill/prompts/extract.d.ts +122 -0
- package/dist/distill/prompts/extract.js +67 -0
- package/dist/distill/prompts/extract.js.map +1 -0
- package/dist/distill/stages/01-cleanup.d.ts +9 -0
- package/dist/distill/stages/01-cleanup.js +67 -0
- package/dist/distill/stages/01-cleanup.js.map +1 -0
- package/dist/distill/stages/02-normalize.d.ts +9 -0
- package/dist/distill/stages/02-normalize.js +76 -0
- package/dist/distill/stages/02-normalize.js.map +1 -0
- package/dist/distill/stages/03-chunk.d.ts +22 -0
- package/dist/distill/stages/03-chunk.js +138 -0
- package/dist/distill/stages/03-chunk.js.map +1 -0
- package/dist/distill/stages/04-compact.d.ts +28 -0
- package/dist/distill/stages/04-compact.js +69 -0
- package/dist/distill/stages/04-compact.js.map +1 -0
- package/dist/distill/stages/05-extract.d.ts +35 -0
- package/dist/distill/stages/05-extract.js +101 -0
- package/dist/distill/stages/05-extract.js.map +1 -0
- package/dist/distill/stages/06-reduce.d.ts +16 -0
- package/dist/distill/stages/06-reduce.js +30 -0
- package/dist/distill/stages/06-reduce.js.map +1 -0
- package/dist/distill/stages/07-memory-normalize.d.ts +27 -0
- package/dist/distill/stages/07-memory-normalize.js +65 -0
- package/dist/distill/stages/07-memory-normalize.js.map +1 -0
- package/dist/distill/stages/08-embed-index.d.ts +31 -0
- package/dist/distill/stages/08-embed-index.js +82 -0
- package/dist/distill/stages/08-embed-index.js.map +1 -0
- package/dist/doctor/checks.d.ts +77 -0
- package/dist/doctor/checks.js +626 -0
- package/dist/doctor/checks.js.map +1 -0
- package/dist/doctor/hardening-checks.d.ts +9 -0
- package/dist/doctor/hardening-checks.js +182 -0
- package/dist/doctor/hardening-checks.js.map +1 -0
- package/dist/doctor/probes/embed-probe.d.ts +19 -0
- package/dist/doctor/probes/embed-probe.js +47 -0
- package/dist/doctor/probes/embed-probe.js.map +1 -0
- package/dist/doctor/probes/llm-chat-probe.d.ts +11 -0
- package/dist/doctor/probes/llm-chat-probe.js +41 -0
- package/dist/doctor/probes/llm-chat-probe.js.map +1 -0
- package/dist/doctor/probes/plugin-coexistence.d.ts +14 -0
- package/dist/doctor/probes/plugin-coexistence.js +60 -0
- package/dist/doctor/probes/plugin-coexistence.js.map +1 -0
- package/dist/doctor/runner.d.ts +17 -0
- package/dist/doctor/runner.js +53 -0
- package/dist/doctor/runner.js.map +1 -0
- package/dist/doctor/types.d.ts +12 -0
- package/dist/doctor/types.js +2 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/entity/backfill.d.ts +30 -0
- package/dist/entity/backfill.js +55 -0
- package/dist/entity/backfill.js.map +1 -0
- package/dist/entity/extract-entities.d.ts +27 -0
- package/dist/entity/extract-entities.js +86 -0
- package/dist/entity/extract-entities.js.map +1 -0
- package/dist/entity/normalize.d.ts +17 -0
- package/dist/entity/normalize.js +20 -0
- package/dist/entity/normalize.js.map +1 -0
- package/dist/eval/harness.d.ts +96 -0
- package/dist/eval/harness.js +119 -0
- package/dist/eval/harness.js.map +1 -0
- package/dist/eval/metrics.d.ts +23 -0
- package/dist/eval/metrics.js +44 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/log/correlation.d.ts +24 -0
- package/dist/log/correlation.js +33 -0
- package/dist/log/correlation.js.map +1 -0
- package/dist/log/logger.d.ts +38 -0
- package/dist/log/logger.js +129 -0
- package/dist/log/logger.js.map +1 -0
- package/dist/log/scrub.d.ts +33 -0
- package/dist/log/scrub.js +91 -0
- package/dist/log/scrub.js.map +1 -0
- package/dist/mcp/server.d.ts +36 -0
- package/dist/mcp/server.js +553 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/memory-tool/adapter.d.ts +73 -0
- package/dist/memory-tool/adapter.js +269 -0
- package/dist/memory-tool/adapter.js.map +1 -0
- package/dist/pipeline/errors.d.ts +21 -0
- package/dist/pipeline/errors.js +34 -0
- package/dist/pipeline/errors.js.map +1 -0
- package/dist/pipeline/failure-classifier.d.ts +13 -0
- package/dist/pipeline/failure-classifier.js +72 -0
- package/dist/pipeline/failure-classifier.js.map +1 -0
- package/dist/pipeline/handler-ctx-ext.d.ts +23 -0
- package/dist/pipeline/handler-ctx-ext.js +19 -0
- package/dist/pipeline/handler-ctx-ext.js.map +1 -0
- package/dist/pipeline/handler.d.ts +20 -0
- package/dist/pipeline/handler.js +2 -0
- package/dist/pipeline/handler.js.map +1 -0
- package/dist/pipeline/handlers/cleanup.d.ts +14 -0
- package/dist/pipeline/handlers/cleanup.js +47 -0
- package/dist/pipeline/handlers/cleanup.js.map +1 -0
- package/dist/pipeline/handlers/consolidate.d.ts +8 -0
- package/dist/pipeline/handlers/consolidate.js +23 -0
- package/dist/pipeline/handlers/consolidate.js.map +1 -0
- package/dist/pipeline/handlers/distill-events.d.ts +15 -0
- package/dist/pipeline/handlers/distill-events.js +134 -0
- package/dist/pipeline/handlers/distill-events.js.map +1 -0
- package/dist/pipeline/handlers/distill.d.ts +17 -0
- package/dist/pipeline/handlers/distill.js +110 -0
- package/dist/pipeline/handlers/distill.js.map +1 -0
- package/dist/pipeline/handlers/reembed.d.ts +10 -0
- package/dist/pipeline/handlers/reembed.js +34 -0
- package/dist/pipeline/handlers/reembed.js.map +1 -0
- package/dist/pipeline/job-repo.d.ts +86 -0
- package/dist/pipeline/job-repo.js +168 -0
- package/dist/pipeline/job-repo.js.map +1 -0
- package/dist/pipeline/mock-providers.d.ts +49 -0
- package/dist/pipeline/mock-providers.js +175 -0
- package/dist/pipeline/mock-providers.js.map +1 -0
- package/dist/pipeline/registry.d.ts +15 -0
- package/dist/pipeline/registry.js +20 -0
- package/dist/pipeline/registry.js.map +1 -0
- package/dist/pipeline/worker.d.ts +41 -0
- package/dist/pipeline/worker.js +167 -0
- package/dist/pipeline/worker.js.map +1 -0
- package/dist/providers/embed/azure-openai.d.ts +25 -0
- package/dist/providers/embed/azure-openai.js +138 -0
- package/dist/providers/embed/azure-openai.js.map +1 -0
- package/dist/providers/embed/ollama.d.ts +17 -0
- package/dist/providers/embed/ollama.js +106 -0
- package/dist/providers/embed/ollama.js.map +1 -0
- package/dist/providers/index.d.ts +19 -0
- package/dist/providers/index.js +72 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/llm/azure-openai.d.ts +20 -0
- package/dist/providers/llm/azure-openai.js +135 -0
- package/dist/providers/llm/azure-openai.js.map +1 -0
- package/dist/providers/llm/ollama.d.ts +13 -0
- package/dist/providers/llm/ollama.js +113 -0
- package/dist/providers/llm/ollama.js.map +1 -0
- package/dist/providers/llm/pricing.d.ts +21 -0
- package/dist/providers/llm/pricing.js +22 -0
- package/dist/providers/llm/pricing.js.map +1 -0
- package/dist/recall/pack.d.ts +32 -0
- package/dist/recall/pack.js +90 -0
- package/dist/recall/pack.js.map +1 -0
- package/dist/recall/policy.d.ts +39 -0
- package/dist/recall/policy.js +96 -0
- package/dist/recall/policy.js.map +1 -0
- package/dist/redact/detectors.d.ts +20 -0
- package/dist/redact/detectors.js +85 -0
- package/dist/redact/detectors.js.map +1 -0
- package/dist/redact/entropy.d.ts +24 -0
- package/dist/redact/entropy.js +77 -0
- package/dist/redact/entropy.js.map +1 -0
- package/dist/redact/index.d.ts +47 -0
- package/dist/redact/index.js +165 -0
- package/dist/redact/index.js.map +1 -0
- package/dist/search/fuse.d.ts +108 -0
- package/dist/search/fuse.js +135 -0
- package/dist/search/fuse.js.map +1 -0
- package/dist/search/query.d.ts +28 -0
- package/dist/search/query.js +70 -0
- package/dist/search/query.js.map +1 -0
- package/dist/search/search.d.ts +164 -0
- package/dist/search/search.js +310 -0
- package/dist/search/search.js.map +1 -0
- package/dist/server/app.d.ts +17 -0
- package/dist/server/app.js +133 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/health-state.d.ts +29 -0
- package/dist/server/health-state.js +28 -0
- package/dist/server/health-state.js.map +1 -0
- package/dist/server/lib/network.d.ts +12 -0
- package/dist/server/lib/network.js +16 -0
- package/dist/server/lib/network.js.map +1 -0
- package/dist/server/lib/score-contract.d.ts +36 -0
- package/dist/server/lib/score-contract.js +54 -0
- package/dist/server/lib/score-contract.js.map +1 -0
- package/dist/server/lib/stable-stringify.d.ts +10 -0
- package/dist/server/lib/stable-stringify.js +27 -0
- package/dist/server/lib/stable-stringify.js.map +1 -0
- package/dist/server/lib/wire-meta.d.ts +7 -0
- package/dist/server/lib/wire-meta.js +29 -0
- package/dist/server/lib/wire-meta.js.map +1 -0
- package/dist/server/queries/dashboard.d.ts +142 -0
- package/dist/server/queries/dashboard.js +166 -0
- package/dist/server/queries/dashboard.js.map +1 -0
- package/dist/server/routes/consolidation.d.ts +14 -0
- package/dist/server/routes/consolidation.js +67 -0
- package/dist/server/routes/consolidation.js.map +1 -0
- package/dist/server/routes/dashboard-api-html.d.ts +15 -0
- package/dist/server/routes/dashboard-api-html.js +144 -0
- package/dist/server/routes/dashboard-api-html.js.map +1 -0
- package/dist/server/routes/dashboard-consolidation-html.d.ts +26 -0
- package/dist/server/routes/dashboard-consolidation-html.js +202 -0
- package/dist/server/routes/dashboard-consolidation-html.js.map +1 -0
- package/dist/server/routes/dashboard-html.d.ts +15 -0
- package/dist/server/routes/dashboard-html.js +365 -0
- package/dist/server/routes/dashboard-html.js.map +1 -0
- package/dist/server/routes/dashboard-jobs-html.d.ts +18 -0
- package/dist/server/routes/dashboard-jobs-html.js +186 -0
- package/dist/server/routes/dashboard-jobs-html.js.map +1 -0
- package/dist/server/routes/dashboard-search-html.d.ts +18 -0
- package/dist/server/routes/dashboard-search-html.js +189 -0
- package/dist/server/routes/dashboard-search-html.js.map +1 -0
- package/dist/server/routes/dashboard.d.ts +19 -0
- package/dist/server/routes/dashboard.js +68 -0
- package/dist/server/routes/dashboard.js.map +1 -0
- package/dist/server/routes/digest.d.ts +9 -0
- package/dist/server/routes/digest.js +37 -0
- package/dist/server/routes/digest.js.map +1 -0
- package/dist/server/routes/entities.d.ts +12 -0
- package/dist/server/routes/entities.js +46 -0
- package/dist/server/routes/entities.js.map +1 -0
- package/dist/server/routes/health.d.ts +14 -0
- package/dist/server/routes/health.js +100 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/ingest.d.ts +209 -0
- package/dist/server/routes/ingest.js +454 -0
- package/dist/server/routes/ingest.js.map +1 -0
- package/dist/server/routes/lifecycle.d.ts +21 -0
- package/dist/server/routes/lifecycle.js +132 -0
- package/dist/server/routes/lifecycle.js.map +1 -0
- package/dist/server/routes/mcp.d.ts +15 -0
- package/dist/server/routes/mcp.js +36 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/memory-tool.d.ts +14 -0
- package/dist/server/routes/memory-tool.js +28 -0
- package/dist/server/routes/memory-tool.js.map +1 -0
- package/dist/server/routes/memory.d.ts +7 -0
- package/dist/server/routes/memory.js +19 -0
- package/dist/server/routes/memory.js.map +1 -0
- package/dist/server/routes/recall.d.ts +15 -0
- package/dist/server/routes/recall.js +74 -0
- package/dist/server/routes/recall.js.map +1 -0
- package/dist/server/routes/search.d.ts +12 -0
- package/dist/server/routes/search.js +203 -0
- package/dist/server/routes/search.js.map +1 -0
- package/dist/server/routes/version.d.ts +2 -0
- package/dist/server/routes/version.js +11 -0
- package/dist/server/routes/version.js.map +1 -0
- package/dist/server/routes/why.d.ts +9 -0
- package/dist/server/routes/why.js +38 -0
- package/dist/server/routes/why.js.map +1 -0
- package/dist/service/index.d.ts +10 -0
- package/dist/service/index.js +25 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install-flow.d.ts +18 -0
- package/dist/service/install-flow.js +47 -0
- package/dist/service/install-flow.js.map +1 -0
- package/dist/service/instance-lock.d.ts +26 -0
- package/dist/service/instance-lock.js +150 -0
- package/dist/service/instance-lock.js.map +1 -0
- package/dist/service/launchd.d.ts +11 -0
- package/dist/service/launchd.js +196 -0
- package/dist/service/launchd.js.map +1 -0
- package/dist/service/schtasks.d.ts +31 -0
- package/dist/service/schtasks.js +274 -0
- package/dist/service/schtasks.js.map +1 -0
- package/dist/service/shim.d.ts +21 -0
- package/dist/service/shim.js +80 -0
- package/dist/service/shim.js.map +1 -0
- package/dist/service/systemd.d.ts +11 -0
- package/dist/service/systemd.js +150 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/task-xml.d.ts +36 -0
- package/dist/service/task-xml.js +91 -0
- package/dist/service/task-xml.js.map +1 -0
- package/dist/service/types.d.ts +47 -0
- package/dist/service/types.js +2 -0
- package/dist/service/types.js.map +1 -0
- package/dist/storage/archival.d.ts +29 -0
- package/dist/storage/archival.js +47 -0
- package/dist/storage/archival.js.map +1 -0
- package/dist/storage/bearer-keystore.d.ts +34 -0
- package/dist/storage/bearer-keystore.js +75 -0
- package/dist/storage/bearer-keystore.js.map +1 -0
- package/dist/storage/db.d.ts +37 -0
- package/dist/storage/db.js +92 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/entities.d.ts +71 -0
- package/dist/storage/entities.js +141 -0
- package/dist/storage/entities.js.map +1 -0
- package/dist/storage/ingest-idempotency.d.ts +26 -0
- package/dist/storage/ingest-idempotency.js +29 -0
- package/dist/storage/ingest-idempotency.js.map +1 -0
- package/dist/storage/keystore.d.ts +64 -0
- package/dist/storage/keystore.js +194 -0
- package/dist/storage/keystore.js.map +1 -0
- package/dist/storage/memories.d.ts +51 -0
- package/dist/storage/memories.js +67 -0
- package/dist/storage/memories.js.map +1 -0
- package/dist/storage/memory-events.d.ts +145 -0
- package/dist/storage/memory-events.js +287 -0
- package/dist/storage/memory-events.js.map +1 -0
- package/dist/storage/migrate-encrypt.d.ts +16 -0
- package/dist/storage/migrate-encrypt.js +121 -0
- package/dist/storage/migrate-encrypt.js.map +1 -0
- package/dist/storage/migrate.d.ts +27 -0
- package/dist/storage/migrate.js +105 -0
- package/dist/storage/migrate.js.map +1 -0
- package/dist/storage/redaction-log.d.ts +18 -0
- package/dist/storage/redaction-log.js +27 -0
- package/dist/storage/redaction-log.js.map +1 -0
- package/dist/storage/usefulness.d.ts +115 -0
- package/dist/storage/usefulness.js +203 -0
- package/dist/storage/usefulness.js.map +1 -0
- package/dist/sync/conflict-resolve.d.ts +26 -0
- package/dist/sync/conflict-resolve.js +139 -0
- package/dist/sync/conflict-resolve.js.map +1 -0
- package/dist/sync/puller.d.ts +115 -0
- package/dist/sync/puller.js +173 -0
- package/dist/sync/puller.js.map +1 -0
- package/dist/sync/shipper.d.ts +112 -0
- package/dist/sync/shipper.js +189 -0
- package/dist/sync/shipper.js.map +1 -0
- package/dist/tag-hygiene/backfill.d.ts +50 -0
- package/dist/tag-hygiene/backfill.js +117 -0
- package/dist/tag-hygiene/backfill.js.map +1 -0
- package/dist/tag-hygiene/derive-repo.d.ts +9 -0
- package/dist/tag-hygiene/derive-repo.js +19 -0
- package/dist/tag-hygiene/derive-repo.js.map +1 -0
- package/dist/tag-hygiene/tier2-infer.d.ts +28 -0
- package/dist/tag-hygiene/tier2-infer.js +72 -0
- package/dist/tag-hygiene/tier2-infer.js.map +1 -0
- package/dist/vector/sqlite-vec.d.ts +16 -0
- package/dist/vector/sqlite-vec.js +49 -0
- package/dist/vector/sqlite-vec.js.map +1 -0
- package/migrations/001-init.sql +117 -0
- package/migrations/002-wire-v1.sql +16 -0
- package/migrations/003-expand-memory-types.sql +81 -0
- package/migrations/004-provenance.sql +4 -0
- package/migrations/005-security.sql +12 -0
- package/migrations/006-atom-v3.sql +28 -0
- package/migrations/007-memory-events.sql +30 -0
- package/migrations/008-consolidation.sql +31 -0
- package/migrations/009-tag-hygiene.sql +13 -0
- package/migrations/010-sync-pull.sql +53 -0
- package/migrations/011-embed-dim-migration.sql +28 -0
- package/migrations/012-entities.sql +36 -0
- package/migrations/013-archival.sql +50 -0
- package/package.json +50 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search orchestrator — hybrid FTS5 + vector + score fusion.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. FTS5 BM25 query on memories_fts
|
|
6
|
+
* 2. embed(query) via EmbedProvider → vec.search() (mock or real)
|
|
7
|
+
* 3. fuseHits — merge FTS + cosine scores
|
|
8
|
+
* 4. apply SQL filters (type, repo, project, since) on the fused id set
|
|
9
|
+
* 5. join full Memory records, return top-k hits
|
|
10
|
+
*
|
|
11
|
+
* VecFilter is intentionally empty on vector search calls because sqlite-vec
|
|
12
|
+
* does not support pre-filtering. All filters are applied post-fusion.
|
|
13
|
+
*/
|
|
14
|
+
import type { DB } from '../storage/db.js';
|
|
15
|
+
import type { EmbedProvider } from '../contracts/index.js';
|
|
16
|
+
import type { MemoryType } from '../contracts/index.js';
|
|
17
|
+
export interface SearchFilters {
|
|
18
|
+
type?: string[];
|
|
19
|
+
repo?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Project filter (FEAT-423). Exact match on `memories.project`. A single
|
|
22
|
+
* string → `project = ?`; a string[] → `project IN (...)` (OR-semantics,
|
|
23
|
+
* mirrors `type[]`). Empty array = no constraint. Absent → all projects.
|
|
24
|
+
*/
|
|
25
|
+
project?: string | string[];
|
|
26
|
+
/**
|
|
27
|
+
* Agent filter (FEAT-423 nice-to-have). Exact match on `memories.agent`
|
|
28
|
+
* (the provenance `agent`/`agent_type` populated at ingest). Applied
|
|
29
|
+
* post-fusion exactly like `repo`/`project`; single string or string[]
|
|
30
|
+
* (IN). Absent → all agents. This is a HARD filter; role-scoped soft-boost
|
|
31
|
+
* recall (FEAT-219) is a separate, later ranking concern and does not go here.
|
|
32
|
+
*/
|
|
33
|
+
agent?: string | string[];
|
|
34
|
+
since?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Bitemporal time-travel (FEAT-401, ADR-001/ADR-005): return memories as
|
|
37
|
+
* they stood at this instant (epoch ms) rather than the current snapshot.
|
|
38
|
+
* Absent = current behavior (only currently-valid rows).
|
|
39
|
+
*/
|
|
40
|
+
as_of?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Entity filter (FEAT-402 slice 2 AC-4). Resolved through
|
|
43
|
+
* EntityRepo.resolveIds (AC-9 normalize seam: exact match, then LIKE
|
|
44
|
+
* substring fallback) to one or more entities.id, then intersected with
|
|
45
|
+
* the FTS+vec candidate set BEFORE fusion — the result is all-and-only
|
|
46
|
+
* entity-linked members of that candidate set, not a post-fusion filter.
|
|
47
|
+
* An unresolvable entity name yields zero results (not an unfiltered
|
|
48
|
+
* search).
|
|
49
|
+
*/
|
|
50
|
+
entity?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface SearchHit {
|
|
53
|
+
id: string;
|
|
54
|
+
type: MemoryType;
|
|
55
|
+
text: string;
|
|
56
|
+
score: number;
|
|
57
|
+
source: 'fts' | 'vec' | 'both';
|
|
58
|
+
}
|
|
59
|
+
export interface SearchOpts {
|
|
60
|
+
db: DB;
|
|
61
|
+
embed: EmbedProvider;
|
|
62
|
+
weights: {
|
|
63
|
+
alpha: number;
|
|
64
|
+
beta: number;
|
|
65
|
+
gamma: number;
|
|
66
|
+
delta: number;
|
|
67
|
+
epsilon?: number;
|
|
68
|
+
zeta?: number;
|
|
69
|
+
};
|
|
70
|
+
/** Multiplier used by vector search (cap to limit vector scan) */
|
|
71
|
+
vecK?: number;
|
|
72
|
+
/**
|
|
73
|
+
* SLICE-410-3: when true, search() returns SearchDebugHit[] — the
|
|
74
|
+
* per-candidate fusion intermediates (raw+normalized bm25/cosine,
|
|
75
|
+
* importance, freshness, usefulness, entityBonus, effective weights, and
|
|
76
|
+
* the final fused score) instead of collapsing to SearchHit[]. Every
|
|
77
|
+
* other step (candidate gathering, entity filter, post-fusion SQL
|
|
78
|
+
* filters, validity/as_of, limit, ranking order) is unchanged — debug is
|
|
79
|
+
* purely an alternate projection of the same fused list, so debug:false
|
|
80
|
+
* or omitted is byte-identical to pre-change behavior (AC-2).
|
|
81
|
+
*/
|
|
82
|
+
debug?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Per-candidate fusion breakdown (SLICE-410-3 AC-1) — the upstream contract
|
|
86
|
+
* for SLICE-410-6's search-debug dashboard page. Mirrors the components
|
|
87
|
+
* `fuseHits`/`fuseScores` (fuse.ts) compute internally and normally discard.
|
|
88
|
+
*
|
|
89
|
+
* Sentinel (AC-4): when a leg has no hit for this candidate (e.g. embed
|
|
90
|
+
* provider down → no vector leg at all), that leg's `raw` is `null` and
|
|
91
|
+
* `normalized` is `0` — identical to the no-signal default `fuseHits`
|
|
92
|
+
* already uses internally, so `score` stays reproducible from these fields
|
|
93
|
+
* even in a degraded (FTS-only or vec-only) run.
|
|
94
|
+
*
|
|
95
|
+
* `usefulness`/`entityBonus`/`weights` are always the *effective* values
|
|
96
|
+
* actually fed into `fuseScores` (defaults resolved, e.g. usefulness 0.5 /
|
|
97
|
+
* entityBonus 0 / zeta 0) so `score` can be reconstructed exactly as:
|
|
98
|
+
* weights.alpha * bm25.normalized + weights.beta * cosine.normalized
|
|
99
|
+
* + weights.gamma * importance + weights.delta * freshness
|
|
100
|
+
* + weights.epsilon * usefulness + weights.zeta * entityBonus
|
|
101
|
+
*/
|
|
102
|
+
export interface SearchDebugHit {
|
|
103
|
+
id: string;
|
|
104
|
+
source: 'fts' | 'vec' | 'both';
|
|
105
|
+
bm25: {
|
|
106
|
+
raw: number | null;
|
|
107
|
+
normalized: number;
|
|
108
|
+
};
|
|
109
|
+
cosine: {
|
|
110
|
+
raw: number | null;
|
|
111
|
+
normalized: number;
|
|
112
|
+
};
|
|
113
|
+
importance: number;
|
|
114
|
+
freshness: number;
|
|
115
|
+
usefulness: number;
|
|
116
|
+
entityBonus: number;
|
|
117
|
+
weights: {
|
|
118
|
+
alpha: number;
|
|
119
|
+
beta: number;
|
|
120
|
+
gamma: number;
|
|
121
|
+
delta: number;
|
|
122
|
+
epsilon: number;
|
|
123
|
+
zeta: number;
|
|
124
|
+
};
|
|
125
|
+
score: number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Bitemporal validity SQL clause (FEAT-401) — the ONE shared filter used by
|
|
129
|
+
* every caller of search() (GET /search, POST /recall, the eval harness).
|
|
130
|
+
* There is deliberately no second implementation anywhere else: the CLI
|
|
131
|
+
* `--as-of` flag and the API `as_of` filter both terminate here because the
|
|
132
|
+
* CLI is a thin HTTP client of the same routes that call search().
|
|
133
|
+
*
|
|
134
|
+
* - No as_of (undefined): current snapshot — only rows with valid_to IS
|
|
135
|
+
* NULL surface, byte-identical to pre-FEAT-401 behavior (AC-2).
|
|
136
|
+
* - as_of = T: the row valid AT INSTANT T — valid_from <= T AND (valid_to
|
|
137
|
+
* IS NULL OR valid_to > T). Half-open interval [valid_from, valid_to):
|
|
138
|
+
* at the exact instant a supersede/invalidate event lands, the new
|
|
139
|
+
* generation is already the one considered valid (AC-5).
|
|
140
|
+
*/
|
|
141
|
+
export declare function validityFilterClause(asOf?: number): {
|
|
142
|
+
clause: string;
|
|
143
|
+
params: number[];
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Parse an `as_of` wire value (ISO-8601 date-time string) into epoch ms.
|
|
147
|
+
* Shared by every route that accepts the filter (GET /search query param,
|
|
148
|
+
* POST /recall body) so a malformed value is rejected identically everywhere
|
|
149
|
+
* — one parsing path, not a per-route reimplementation. Returns undefined
|
|
150
|
+
* for an absent/empty value; throws for a present-but-unparseable value so
|
|
151
|
+
* callers can turn it into a 400.
|
|
152
|
+
*/
|
|
153
|
+
export declare function parseAsOf(value: string | undefined): number | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Deterministic fake vector for testing — seeded by text hash, dim
|
|
156
|
+
* defaults to DEFAULT_EMBED_DIM (1024). Exported so tests can call it
|
|
157
|
+
* directly without importing the EmbedProvider. Pass `dim` to generate a
|
|
158
|
+
* fixture vector matching a non-default schema (FEAT-409 AC-2).
|
|
159
|
+
*/
|
|
160
|
+
export declare function makeFakeVec(text: string, dim?: number): Float32Array;
|
|
161
|
+
export declare function search(query: string, filters: SearchFilters, limit: number, opts: SearchOpts & {
|
|
162
|
+
debug: true;
|
|
163
|
+
}): Promise<SearchDebugHit[]>;
|
|
164
|
+
export declare function search(query: string, filters: SearchFilters, limit: number, opts: SearchOpts): Promise<SearchHit[]>;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search orchestrator — hybrid FTS5 + vector + score fusion.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. FTS5 BM25 query on memories_fts
|
|
6
|
+
* 2. embed(query) via EmbedProvider → vec.search() (mock or real)
|
|
7
|
+
* 3. fuseHits — merge FTS + cosine scores
|
|
8
|
+
* 4. apply SQL filters (type, repo, project, since) on the fused id set
|
|
9
|
+
* 5. join full Memory records, return top-k hits
|
|
10
|
+
*
|
|
11
|
+
* VecFilter is intentionally empty on vector search calls because sqlite-vec
|
|
12
|
+
* does not support pre-filtering. All filters are applied post-fusion.
|
|
13
|
+
*/
|
|
14
|
+
import { DEFAULT_EMBED_DIM } from '../contracts/embed.js';
|
|
15
|
+
import { fuseHits, normalizeScores } from './fuse.js';
|
|
16
|
+
import { SqliteVecStore } from '../vector/sqlite-vec.js';
|
|
17
|
+
import { usefulnessScores } from '../storage/usefulness.js';
|
|
18
|
+
import { EntityRepo } from '../storage/entities.js';
|
|
19
|
+
/**
|
|
20
|
+
* Sanitize a free-form query string for safe use with the FTS5 `MATCH` operator.
|
|
21
|
+
*
|
|
22
|
+
* FTS5 treats several characters as operators (`-` negation, `*` wildcard,
|
|
23
|
+
* `"` phrase, `^` column, `AND`/`OR`/`NOT` connectives). Without sanitization,
|
|
24
|
+
* a query like `sqlite-vec` triggers `fts5: syntax error near "-"` because `-`
|
|
25
|
+
* is parsed as a negation prefix.
|
|
26
|
+
*
|
|
27
|
+
* Strategy: split on whitespace, wrap each token in double quotes (treating
|
|
28
|
+
* each as a literal phrase), and escape embedded `"` by doubling it per the
|
|
29
|
+
* FTS5 phrase-literal rule. Multi-token queries become implicit AND.
|
|
30
|
+
*
|
|
31
|
+
* Trade-off: explicit FTS5 operators (e.g., `cat OR dog`, `"exact phrase"`,
|
|
32
|
+
* `prefix*`) are NOT honored in v1 — every input is treated as a bag of
|
|
33
|
+
* literal phrases. This is the right default for an agent-driven search
|
|
34
|
+
* surface; an `advanced` flag can be added later if needed.
|
|
35
|
+
*/
|
|
36
|
+
function escapeFtsQuery(q) {
|
|
37
|
+
return q.trim().split(/\s+/).map(t => `"${t.replace(/"/g, '""')}"`).join(' ');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Bitemporal validity SQL clause (FEAT-401) — the ONE shared filter used by
|
|
41
|
+
* every caller of search() (GET /search, POST /recall, the eval harness).
|
|
42
|
+
* There is deliberately no second implementation anywhere else: the CLI
|
|
43
|
+
* `--as-of` flag and the API `as_of` filter both terminate here because the
|
|
44
|
+
* CLI is a thin HTTP client of the same routes that call search().
|
|
45
|
+
*
|
|
46
|
+
* - No as_of (undefined): current snapshot — only rows with valid_to IS
|
|
47
|
+
* NULL surface, byte-identical to pre-FEAT-401 behavior (AC-2).
|
|
48
|
+
* - as_of = T: the row valid AT INSTANT T — valid_from <= T AND (valid_to
|
|
49
|
+
* IS NULL OR valid_to > T). Half-open interval [valid_from, valid_to):
|
|
50
|
+
* at the exact instant a supersede/invalidate event lands, the new
|
|
51
|
+
* generation is already the one considered valid (AC-5).
|
|
52
|
+
*/
|
|
53
|
+
export function validityFilterClause(asOf) {
|
|
54
|
+
if (asOf === undefined) {
|
|
55
|
+
return { clause: 'valid_to IS NULL', params: [] };
|
|
56
|
+
}
|
|
57
|
+
return { clause: 'valid_from <= ? AND (valid_to IS NULL OR valid_to > ?)', params: [asOf, asOf] };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse an `as_of` wire value (ISO-8601 date-time string) into epoch ms.
|
|
61
|
+
* Shared by every route that accepts the filter (GET /search query param,
|
|
62
|
+
* POST /recall body) so a malformed value is rejected identically everywhere
|
|
63
|
+
* — one parsing path, not a per-route reimplementation. Returns undefined
|
|
64
|
+
* for an absent/empty value; throws for a present-but-unparseable value so
|
|
65
|
+
* callers can turn it into a 400.
|
|
66
|
+
*/
|
|
67
|
+
export function parseAsOf(value) {
|
|
68
|
+
if (value === undefined || value === '')
|
|
69
|
+
return undefined;
|
|
70
|
+
const ms = Date.parse(value);
|
|
71
|
+
if (Number.isNaN(ms)) {
|
|
72
|
+
throw new Error(`invalid as_of value: ${value} (expected ISO-8601 date-time)`);
|
|
73
|
+
}
|
|
74
|
+
return ms;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Deterministic fake vector for testing — seeded by text hash, dim
|
|
78
|
+
* defaults to DEFAULT_EMBED_DIM (1024). Exported so tests can call it
|
|
79
|
+
* directly without importing the EmbedProvider. Pass `dim` to generate a
|
|
80
|
+
* fixture vector matching a non-default schema (FEAT-409 AC-2).
|
|
81
|
+
*/
|
|
82
|
+
export function makeFakeVec(text, dim = DEFAULT_EMBED_DIM) {
|
|
83
|
+
const v = new Float32Array(dim);
|
|
84
|
+
let hash = 0;
|
|
85
|
+
for (let i = 0; i < text.length; i++) {
|
|
86
|
+
hash = (hash * 31 + text.charCodeAt(i)) & 0xffffffff;
|
|
87
|
+
}
|
|
88
|
+
for (let i = 0; i < dim; i++) {
|
|
89
|
+
v[i] = Math.sin(hash * 0.001 + i * 0.01);
|
|
90
|
+
}
|
|
91
|
+
return v;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Compute the ζ entity-relevance bonus map (FEAT-402 slice 2 AC-6): for
|
|
95
|
+
* every known entity whose normalized name appears as a substring of the
|
|
96
|
+
* (lowercased) query text, any candidate id linked to that entity gets a
|
|
97
|
+
* bonus of 1. Only called when `search.zeta > 0` — with the default
|
|
98
|
+
* zeta=0 this function never runs, which is what makes the AC-6 snapshot
|
|
99
|
+
* guarantee (identical ranking at zeta=0) hold structurally, not just
|
|
100
|
+
* numerically.
|
|
101
|
+
*/
|
|
102
|
+
function entityBonusForQuery(db, query, candidateIds) {
|
|
103
|
+
const q = query.trim().toLowerCase();
|
|
104
|
+
if (!q || candidateIds.size === 0)
|
|
105
|
+
return new Map();
|
|
106
|
+
const entityRows = db.prepare('SELECT id, name FROM entities').all();
|
|
107
|
+
const matchedEntityIds = entityRows.filter(r => r.name && q.includes(r.name)).map(r => r.id);
|
|
108
|
+
if (matchedEntityIds.length === 0)
|
|
109
|
+
return new Map();
|
|
110
|
+
const idPh = Array.from(candidateIds).map(() => '?').join(',');
|
|
111
|
+
const entPh = matchedEntityIds.map(() => '?').join(',');
|
|
112
|
+
const rows = db.prepare(`SELECT DISTINCT memory_id FROM memory_entities WHERE memory_id IN (${idPh}) AND entity_id IN (${entPh})`).all(...candidateIds, ...matchedEntityIds);
|
|
113
|
+
const bonus = new Map();
|
|
114
|
+
for (const row of rows)
|
|
115
|
+
bonus.set(row.memory_id, 1);
|
|
116
|
+
return bonus;
|
|
117
|
+
}
|
|
118
|
+
export async function search(query, filters, limit, opts) {
|
|
119
|
+
const { db, embed, weights } = opts;
|
|
120
|
+
const vecK = opts.vecK ?? Math.max(limit * 4, 50);
|
|
121
|
+
// 1. FTS5 BM25 — run only if query is non-empty
|
|
122
|
+
const ftsHits = [];
|
|
123
|
+
if (query.trim()) {
|
|
124
|
+
const ftsQuery = escapeFtsQuery(query);
|
|
125
|
+
try {
|
|
126
|
+
const rows = db.prepare(`
|
|
127
|
+
SELECT m.id, bm25(memories_fts) AS bm25
|
|
128
|
+
FROM memories_fts
|
|
129
|
+
JOIN memories m ON m.rowid = memories_fts.rowid
|
|
130
|
+
WHERE memories_fts MATCH ?
|
|
131
|
+
ORDER BY bm25
|
|
132
|
+
LIMIT ?
|
|
133
|
+
`).all(ftsQuery, vecK);
|
|
134
|
+
ftsHits.push(...rows);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// FTS5 rejected the query (rare with escapeFtsQuery sanitization).
|
|
138
|
+
// Fall through to vector-only path.
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 2. Vector search — always attempt; if embed fails, fall back to FTS-only
|
|
142
|
+
const vecHits = [];
|
|
143
|
+
try {
|
|
144
|
+
const vecs = await embed.embed([query]);
|
|
145
|
+
const queryVec = vecs[0];
|
|
146
|
+
if (!queryVec)
|
|
147
|
+
throw new Error('embed provider returned empty result');
|
|
148
|
+
const vecStore = new SqliteVecStore(db, embed.dim);
|
|
149
|
+
// Pass empty filter to vec adapter — post-fusion filters applied below
|
|
150
|
+
const raw = await vecStore.search(queryVec, vecK);
|
|
151
|
+
vecHits.push(...raw.map(h => ({ id: h.id, cosine: h.score })));
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Vector search unavailable (no rows, no provider) — FTS-only mode
|
|
155
|
+
}
|
|
156
|
+
// 2b. Entity filter (FEAT-402 slice 2 AC-4) — resolve `entity` to entity
|
|
157
|
+
// ids (AC-9 normalize seam) and intersect the FTS+vec candidate set BEFORE
|
|
158
|
+
// fusion, so the result is all-and-only entity-linked members of that
|
|
159
|
+
// candidate set. An entity name that resolves to zero entities filters the
|
|
160
|
+
// candidate set to empty (not "unfiltered") — search() returns [] below.
|
|
161
|
+
let filteredFtsHits = ftsHits;
|
|
162
|
+
let filteredVecHits = vecHits;
|
|
163
|
+
if (filters.entity !== undefined) {
|
|
164
|
+
const entityRepo = new EntityRepo(db);
|
|
165
|
+
const entityIds = entityRepo.resolveIds(filters.entity);
|
|
166
|
+
const linkedIds = entityRepo.memoryIdsForEntities(entityIds);
|
|
167
|
+
filteredFtsHits = ftsHits.filter(h => linkedIds.has(h.id));
|
|
168
|
+
filteredVecHits = vecHits.filter(h => linkedIds.has(h.id));
|
|
169
|
+
}
|
|
170
|
+
// 3. Load meta for all candidate ids (importance + created_at for freshness)
|
|
171
|
+
const allIds = new Set([...filteredFtsHits.map(h => h.id), ...filteredVecHits.map(h => h.id)]);
|
|
172
|
+
if (allIds.size === 0)
|
|
173
|
+
return [];
|
|
174
|
+
const placeholders = Array.from(allIds).map(() => '?').join(',');
|
|
175
|
+
const metaRows = db.prepare(`SELECT id, importance, created_at FROM memories WHERE id IN (${placeholders})`).all(...allIds);
|
|
176
|
+
const metaMap = new Map(metaRows.map(r => [r.id, { importance: r.importance, created_at: r.created_at }]));
|
|
177
|
+
// 4. Fuse — usefulness (ADR-010 v1.x) joins as the ε component. ζ
|
|
178
|
+
// (FEAT-402 AC-6) joins as an entity-relevance bonus: DEFAULT 0 (config
|
|
179
|
+
// search.zeta) means the term is skipped entirely — no query, no DB scan,
|
|
180
|
+
// no change to ranking order versus pre-AC-6 behavior.
|
|
181
|
+
const usefulness = usefulnessScores(db, Array.from(allIds));
|
|
182
|
+
const zeta = weights.zeta ?? 0;
|
|
183
|
+
const entityBonus = zeta > 0 ? entityBonusForQuery(db, query, allIds) : undefined;
|
|
184
|
+
const nowMs = Date.now();
|
|
185
|
+
const fused = fuseHits(filteredFtsHits, filteredVecHits, metaMap, weights, nowMs, undefined, usefulness, entityBonus);
|
|
186
|
+
// 5. Apply post-fusion SQL filters then join full memory records
|
|
187
|
+
// Build filter clauses dynamically
|
|
188
|
+
const filterClauses = [];
|
|
189
|
+
const filterParams = [];
|
|
190
|
+
if (filters.type && filters.type.length > 0) {
|
|
191
|
+
const ph = filters.type.map(() => '?').join(',');
|
|
192
|
+
filterClauses.push(`type IN (${ph})`);
|
|
193
|
+
filterParams.push(...filters.type);
|
|
194
|
+
}
|
|
195
|
+
if (filters.repo !== undefined) {
|
|
196
|
+
filterClauses.push('repo = ?');
|
|
197
|
+
filterParams.push(filters.repo);
|
|
198
|
+
}
|
|
199
|
+
// FEAT-423: project/agent accept a single value (`col = ?`) or a list
|
|
200
|
+
// (`col IN (...)`, OR-semantics like `type[]`). An empty list is treated as
|
|
201
|
+
// no constraint, never as "match nothing".
|
|
202
|
+
const addEqOrIn = (col, val) => {
|
|
203
|
+
if (Array.isArray(val)) {
|
|
204
|
+
if (val.length === 0)
|
|
205
|
+
return;
|
|
206
|
+
filterClauses.push(`${col} IN (${val.map(() => '?').join(',')})`);
|
|
207
|
+
filterParams.push(...val);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
filterClauses.push(`${col} = ?`);
|
|
211
|
+
filterParams.push(val);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
if (filters.project !== undefined)
|
|
215
|
+
addEqOrIn('project', filters.project);
|
|
216
|
+
if (filters.agent !== undefined)
|
|
217
|
+
addEqOrIn('agent', filters.agent);
|
|
218
|
+
if (filters.since !== undefined) {
|
|
219
|
+
filterClauses.push('created_at >= ?');
|
|
220
|
+
filterParams.push(filters.since);
|
|
221
|
+
}
|
|
222
|
+
// Fetch full memory records in one query using IN clause
|
|
223
|
+
const fusedIds = fused.map(h => h.id);
|
|
224
|
+
const idPlaceholders = fusedIds.map(() => '?').join(',');
|
|
225
|
+
// Atom v3 (ADR-001): invalidated memories (valid_to set) must never surface
|
|
226
|
+
// in a current-snapshot recall — why_memory can still fetch them by id
|
|
227
|
+
// directly. FEAT-401: when as_of is set, the snapshot rule is replaced by
|
|
228
|
+
// the bitemporal validity window so a past-valid (now superseded) memory
|
|
229
|
+
// can surface again for a point-in-time query.
|
|
230
|
+
const { clause: validityClause, params: validityParams } = validityFilterClause(filters.as_of);
|
|
231
|
+
const whereFilter = filterClauses.length > 0 ? ` AND ${filterClauses.join(' AND ')}` : '';
|
|
232
|
+
const sql = `SELECT id, type, text FROM memories WHERE id IN (${idPlaceholders}) AND ${validityClause}${whereFilter}`;
|
|
233
|
+
const memRows = db.prepare(sql).all(...fusedIds, ...validityParams, ...filterParams);
|
|
234
|
+
const memMap = new Map(memRows.map(r => [r.id, r]));
|
|
235
|
+
// 6a. Debug projection (SLICE-410-3 AC-1) — recompute the same
|
|
236
|
+
// normalization fuseHits() applies internally (normalizeScores is
|
|
237
|
+
// exported from fuse.ts for exactly this reuse) so components are
|
|
238
|
+
// guaranteed consistent with `fused[].score`, without touching fuse.ts.
|
|
239
|
+
if (opts.debug) {
|
|
240
|
+
const bm25RawMap = new Map(filteredFtsHits.map(h => [h.id, h.bm25]));
|
|
241
|
+
const normBm25Arr = normalizeScores(filteredFtsHits.map(h => -h.bm25));
|
|
242
|
+
const normBm25Map = new Map(filteredFtsHits.map((h, i) => [h.id, normBm25Arr[i] ?? 0]));
|
|
243
|
+
const cosineRawMap = new Map(filteredVecHits.map(h => [h.id, h.cosine]));
|
|
244
|
+
const normCosineArr = normalizeScores(filteredVecHits.map(h => h.cosine));
|
|
245
|
+
const normCosineMap = new Map(filteredVecHits.map((h, i) => [h.id, normCosineArr[i] ?? 0]));
|
|
246
|
+
// Freshness half-life: fuse.ts fuseHits() default freshnessDecayDays=30,
|
|
247
|
+
// which search() always uses (passes `undefined` through to that
|
|
248
|
+
// default). Kept identical here so freshness — and thus `score` — stays
|
|
249
|
+
// reproducible from the documented weights (AC-3).
|
|
250
|
+
const freshnessDecayDays = 30;
|
|
251
|
+
// fuseScores() divides the raw weighted sum by the sum of active weights
|
|
252
|
+
// to keep scores in [0,1] (wire contract). Report weightSum-normalized
|
|
253
|
+
// weights here so `score` stays exactly reproducible as
|
|
254
|
+
// Σ weights.* × component from this object alone.
|
|
255
|
+
const rawWeightSum = weights.alpha + weights.beta + weights.gamma + weights.delta +
|
|
256
|
+
(weights.epsilon ?? 0) + zeta;
|
|
257
|
+
const weightSum = rawWeightSum === 0 ? 1 : rawWeightSum;
|
|
258
|
+
const effectiveWeights = {
|
|
259
|
+
alpha: weights.alpha / weightSum,
|
|
260
|
+
beta: weights.beta / weightSum,
|
|
261
|
+
gamma: weights.gamma / weightSum,
|
|
262
|
+
delta: weights.delta / weightSum,
|
|
263
|
+
epsilon: (weights.epsilon ?? 0) / weightSum,
|
|
264
|
+
zeta: zeta / weightSum,
|
|
265
|
+
};
|
|
266
|
+
const debugResults = [];
|
|
267
|
+
for (const hit of fused) {
|
|
268
|
+
if (!memMap.has(hit.id))
|
|
269
|
+
continue; // filtered out, same as SearchHit path
|
|
270
|
+
const meta = metaMap.get(hit.id);
|
|
271
|
+
const importance = meta?.importance ?? 0.5;
|
|
272
|
+
const createdAt = meta?.created_at ?? nowMs;
|
|
273
|
+
const ageDays = (nowMs - createdAt) / (24 * 60 * 60 * 1000);
|
|
274
|
+
const freshness = Math.exp(-ageDays / freshnessDecayDays);
|
|
275
|
+
debugResults.push({
|
|
276
|
+
id: hit.id,
|
|
277
|
+
source: hit.source,
|
|
278
|
+
bm25: { raw: bm25RawMap.get(hit.id) ?? null, normalized: normBm25Map.get(hit.id) ?? 0 },
|
|
279
|
+
cosine: { raw: cosineRawMap.get(hit.id) ?? null, normalized: normCosineMap.get(hit.id) ?? 0 },
|
|
280
|
+
importance,
|
|
281
|
+
freshness,
|
|
282
|
+
usefulness: usefulness.get(hit.id) ?? 0.5,
|
|
283
|
+
entityBonus: entityBonus?.get(hit.id) ?? 0,
|
|
284
|
+
weights: effectiveWeights,
|
|
285
|
+
score: hit.score,
|
|
286
|
+
});
|
|
287
|
+
if (debugResults.length >= limit)
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
return debugResults;
|
|
291
|
+
}
|
|
292
|
+
// 6. Build result — preserve fused ranking order, skip filtered-out ids
|
|
293
|
+
const results = [];
|
|
294
|
+
for (const hit of fused) {
|
|
295
|
+
const mem = memMap.get(hit.id);
|
|
296
|
+
if (!mem)
|
|
297
|
+
continue; // filtered out
|
|
298
|
+
results.push({
|
|
299
|
+
id: hit.id,
|
|
300
|
+
type: mem.type,
|
|
301
|
+
text: mem.text,
|
|
302
|
+
score: hit.score,
|
|
303
|
+
source: hit.source
|
|
304
|
+
});
|
|
305
|
+
if (results.length >= limit)
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
return results;
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAiB,MAAM,WAAW,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgGpD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,wDAAwD,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;AACpG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,KAAyB;IACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,gCAAgC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,MAAc,iBAAiB;IACvE,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC;IACvD,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,EAAM,EAAE,KAAa,EAAE,YAAyB;IAC3E,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAEpD,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC,GAAG,EAAyC,CAAC;IAC5G,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7F,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAEpD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,sEAAsE,IAAI,uBAAuB,KAAK,GAAG,CAC1G,CAAC,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,gBAAgB,CAAiC,CAAC;IAE5E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC;AACf,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAa,EACb,OAAsB,EACtB,KAAa,EACb,IAAgB;IAEhB,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IAElD,gDAAgD;IAChD,MAAM,OAAO,GAAwC,EAAE,CAAC;IACxD,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;OAOvB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAwC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;YACnE,oCAAoC;QACtC,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,OAAO,GAA0C,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACnD,uEAAuE;QACvE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;IACrE,CAAC;IAED,yEAAyE;IACzE,2EAA2E;IAC3E,sEAAsE;IACtE,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,eAAe,GAAG,OAAO,CAAC;IAC9B,IAAI,eAAe,GAAG,OAAO,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC7D,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,6EAA6E;IAC7E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/F,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CACzB,gEAAgE,YAAY,GAAG,CAChF,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkE,CAAC;IAElF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAE3G,kEAAkE;IAClE,wEAAwE;IACxE,0EAA0E;IAC1E,uDAAuD;IACvD,MAAM,UAAU,GAAG,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAEtH,iEAAiE;IACjE,sCAAsC;IACtC,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,YAAY,GAAwB,EAAE,CAAC;IAE7C,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IACD,sEAAsE;IACtE,4EAA4E;IAC5E,2CAA2C;IAC3C,MAAM,SAAS,GAAG,CAAC,GAAwB,EAAE,GAAsB,EAAE,EAAE;QACrE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC7B,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClE,YAAY,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;YACjC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,yDAAyD;IACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,4EAA4E;IAC5E,uEAAuE;IACvE,0EAA0E;IAC1E,yEAAyE;IACzE,+CAA+C;IAC/C,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/F,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,MAAM,GAAG,GAAG,oDAAoD,cAAc,SAAS,cAAc,GAAG,WAAW,EAAE,CAAC;IACtH,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,cAAc,EAAE,GAAG,YAAY,CAA0D,CAAC;IAE9I,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,+DAA+D;IAC/D,kEAAkE;IAClE,kEAAkE;IAClE,wEAAwE;IACxE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,WAAW,GAAG,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAExF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACzE,MAAM,aAAa,GAAG,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1E,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5F,yEAAyE;QACzE,iEAAiE;QACjE,wEAAwE;QACxE,mDAAmD;QACnD,MAAM,kBAAkB,GAAG,EAAE,CAAC;QAC9B,yEAAyE;QACzE,uEAAuE;QACvE,wDAAwD;QACxD,kDAAkD;QAClD,MAAM,YAAY,GAChB,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK;YAC5D,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;QAChC,MAAM,SAAS,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;QACxD,MAAM,gBAAgB,GAAG;YACvB,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,IAAI,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,SAAS;YAChC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,SAAS;YAC3C,IAAI,EAAE,IAAI,GAAG,SAAS;SACvB,CAAC;QAEF,MAAM,YAAY,GAAqB,EAAE,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS,CAAE,uCAAuC;YAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjC,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,GAAG,CAAC;YAC3C,MAAM,SAAS,GAAG,IAAI,EAAE,UAAU,IAAI,KAAK,CAAC;YAC5C,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,GAAG,kBAAkB,CAAC,CAAC;YAE1D,YAAY,CAAC,IAAI,CAAC;gBAChB,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;gBACvF,MAAM,EAAE,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;gBAC7F,UAAU;gBACV,SAAS;gBACT,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG;gBACzC,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;gBAC1C,OAAO,EAAE,gBAAgB;gBACzB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;YACH,IAAI,YAAY,CAAC,MAAM,IAAI,KAAK;gBAAE,MAAM;QAC1C,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,wEAAwE;IACxE,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG;YAAE,SAAS,CAAE,eAAe;QACpC,OAAO,CAAC,IAAI,CAAC;YACX,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK;YAAE,MAAM;IACrC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { DB } from '../storage/db.js';
|
|
3
|
+
import type { EmbedProvider } from '../contracts/index.js';
|
|
4
|
+
import { type Config } from '../config/config.js';
|
|
5
|
+
import type { HealthState } from './health-state.js';
|
|
6
|
+
export interface AppOpts {
|
|
7
|
+
db: DB;
|
|
8
|
+
token: string;
|
|
9
|
+
/** Embed provider injected for search + remember routes. Defaults to fake/noop. */
|
|
10
|
+
embed?: EmbedProvider;
|
|
11
|
+
/** Server config — used by dashboard route for budget cap display. Defaults to defaultConfig(). */
|
|
12
|
+
config?: Config;
|
|
13
|
+
/** Live daemon health snapshot (degraded-start, D3). Optional — /health
|
|
14
|
+
* omits the status/embed fields when absent (e.g. bare test apps). */
|
|
15
|
+
healthState?: HealthState;
|
|
16
|
+
}
|
|
17
|
+
export declare function buildApp(opts: AppOpts): Promise<FastifyInstance>;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import { healthRoute } from './routes/health.js';
|
|
3
|
+
import { versionRoute } from './routes/version.js';
|
|
4
|
+
import { ingestRoute } from './routes/ingest.js';
|
|
5
|
+
import { searchRoute } from './routes/search.js';
|
|
6
|
+
import { memoryRoute } from './routes/memory.js';
|
|
7
|
+
import { lifecycleRoutes } from './routes/lifecycle.js';
|
|
8
|
+
import { whyRoute } from './routes/why.js';
|
|
9
|
+
import { digestRoute } from './routes/digest.js';
|
|
10
|
+
import { recallRoute } from './routes/recall.js';
|
|
11
|
+
import { mcpRoute } from './routes/mcp.js';
|
|
12
|
+
import { dashboardRoute } from './routes/dashboard.js';
|
|
13
|
+
import { dashboardConsolidationRoute } from './routes/dashboard-consolidation-html.js';
|
|
14
|
+
import { dashboardJobsRoute } from './routes/dashboard-jobs-html.js';
|
|
15
|
+
import { dashboardSearchRoute } from './routes/dashboard-search-html.js';
|
|
16
|
+
import { dashboardApiRoute } from './routes/dashboard-api-html.js';
|
|
17
|
+
import { memoryToolRoute } from './routes/memory-tool.js';
|
|
18
|
+
import { consolidationRoutes } from './routes/consolidation.js';
|
|
19
|
+
import { entitiesRoute } from './routes/entities.js';
|
|
20
|
+
import { makeFakeVec } from '../search/search.js';
|
|
21
|
+
import { childLogger } from '../log/logger.js';
|
|
22
|
+
import { newRequestId, runWithRequestId } from '../log/correlation.js';
|
|
23
|
+
import { defaultConfig } from '../config/config.js';
|
|
24
|
+
import { isLoopbackHost } from './lib/network.js';
|
|
25
|
+
/** Default no-op embed provider used when no real provider is injected.
|
|
26
|
+
* FEAT-409: dim derived from config.embedding.dim (defaults to
|
|
27
|
+
* DEFAULT_EMBED_DIM via defaultConfig()) rather than a literal, so the
|
|
28
|
+
* noop provider's fake vectors always match whatever schema dim is live. */
|
|
29
|
+
function makeNoopEmbed(dim) {
|
|
30
|
+
return {
|
|
31
|
+
name: 'ollama',
|
|
32
|
+
model: 'noop',
|
|
33
|
+
dim,
|
|
34
|
+
embed: async (texts) => texts.map(t => makeFakeVec(t, dim)),
|
|
35
|
+
health: async () => ({ ok: false, model: 'noop', dim, error: 'no provider configured' })
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export async function buildApp(opts) {
|
|
39
|
+
// Fastify's internal logger is disabled. We emit request lifecycle logs
|
|
40
|
+
// manually via the onResponse hook below, using our pino instance + the
|
|
41
|
+
// request_id we generate in onRequest. This sidesteps a type incompatibility
|
|
42
|
+
// between FastifyBaseLogger and FastifyInstance<never logger>.
|
|
43
|
+
const app = Fastify({
|
|
44
|
+
logger: false,
|
|
45
|
+
// Long Codex/Claude sessions routinely exceed Fastify's 1MiB default —
|
|
46
|
+
// an oversized transcript should not 413 (wire: POST /ingest/transcript).
|
|
47
|
+
bodyLimit: 10 * 1024 * 1024,
|
|
48
|
+
// A stuck handler must not hold a connection forever (recall with a cold
|
|
49
|
+
// embed can be slow, but 60s is the ceiling — matches the LLM timeout).
|
|
50
|
+
requestTimeout: 60_000,
|
|
51
|
+
});
|
|
52
|
+
const config = opts.config ?? defaultConfig();
|
|
53
|
+
const embed = opts.embed ?? makeNoopEmbed(config.embedding.dim);
|
|
54
|
+
// Assign a request_id to every incoming request and expose it on the reply header.
|
|
55
|
+
app.addHook('onRequest', async (req, reply) => {
|
|
56
|
+
const requestId = newRequestId();
|
|
57
|
+
// Store on req so downstream hooks / routes can read it
|
|
58
|
+
req['requestId'] = requestId;
|
|
59
|
+
// Bind to async local storage for propagation into jobs queued from this request
|
|
60
|
+
runWithRequestId(requestId, () => {
|
|
61
|
+
// noop — storage set; pino child created in route handlers
|
|
62
|
+
});
|
|
63
|
+
void reply.header('x-request-id', requestId);
|
|
64
|
+
});
|
|
65
|
+
// Log HTTP request start + completion with required fields.
|
|
66
|
+
app.addHook('onResponse', (req, reply, done) => {
|
|
67
|
+
const requestId = req['requestId'];
|
|
68
|
+
const log = childLogger({ request_id: requestId ?? 'unknown' });
|
|
69
|
+
log.info({
|
|
70
|
+
method: req.method,
|
|
71
|
+
path: req.url,
|
|
72
|
+
status: reply.statusCode,
|
|
73
|
+
}, 'request complete');
|
|
74
|
+
done();
|
|
75
|
+
});
|
|
76
|
+
// Auth check — scrub the Authorization header value from any error logs.
|
|
77
|
+
// /dashboard and its sub-pages (/dashboard/consolidation, /dashboard/jobs,
|
|
78
|
+
// /dashboard/search — FEAT-410) validate their own token via ?token= query
|
|
79
|
+
// param or cookie — always exempt on prefix, not just the exact path.
|
|
80
|
+
// /health and /version are public ONLY while the daemon is bound to loopback
|
|
81
|
+
// (default). FEAT-406: opting into a non-local bind (config.network.host set
|
|
82
|
+
// to anything but 127.0.0.1/localhost/::1) requires Bearer auth on BOTH
|
|
83
|
+
// routes together — isLoopbackHost is the one predicate that decides this,
|
|
84
|
+
// so the bind and the auth boundary can never drift apart.
|
|
85
|
+
const isLocalBind = isLoopbackHost(config.network.host);
|
|
86
|
+
app.addHook('preHandler', async (req, reply) => {
|
|
87
|
+
const path = req.url.split('?')[0];
|
|
88
|
+
if (path === '/dashboard' || path?.startsWith('/dashboard/'))
|
|
89
|
+
return;
|
|
90
|
+
if (isLocalBind && (path === '/health' || path === '/version'))
|
|
91
|
+
return;
|
|
92
|
+
const auth = req.headers.authorization;
|
|
93
|
+
if (auth !== `Bearer ${opts.token}`) {
|
|
94
|
+
const requestId = req['requestId'];
|
|
95
|
+
childLogger({ request_id: requestId ?? 'unknown' }).warn({ method: req.method, path: req.url }, 'unauthorized request');
|
|
96
|
+
return reply.code(401).send({ error: 'unauthorized' });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// Unhandled route errors: log the full error server-side, return a
|
|
100
|
+
// sanitized body (no stack, no internals) with the original status when a
|
|
101
|
+
// route set one (e.g. Fastify's own 413/400), else 500. Existing 4xx
|
|
102
|
+
// paths return their own bodies and never reach this handler.
|
|
103
|
+
app.setErrorHandler((rawErr, req, reply) => {
|
|
104
|
+
const err = rawErr;
|
|
105
|
+
const requestId = req['requestId'];
|
|
106
|
+
const status = typeof err.statusCode === 'number' && err.statusCode >= 400 ? err.statusCode : 500;
|
|
107
|
+
childLogger({ request_id: requestId ?? 'unknown' }).error({ method: req.method, path: req.url, status, error_message: err.message, error_kind: err.name }, 'request failed');
|
|
108
|
+
void reply.code(status).send({
|
|
109
|
+
ok: false,
|
|
110
|
+
error: { code: status === 500 ? 'internal' : String(err.code ?? status), message: status === 500 ? 'internal error' : err.message },
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
await app.register(healthRoute(config, opts.db, opts.healthState));
|
|
114
|
+
await app.register(versionRoute);
|
|
115
|
+
await app.register(ingestRoute(opts.db, config));
|
|
116
|
+
await app.register(searchRoute(opts.db, embed, config));
|
|
117
|
+
await app.register(memoryRoute(opts.db));
|
|
118
|
+
await app.register(lifecycleRoutes(opts.db));
|
|
119
|
+
await app.register(whyRoute(opts.db));
|
|
120
|
+
await app.register(digestRoute(opts.db));
|
|
121
|
+
await app.register(recallRoute(opts.db, config));
|
|
122
|
+
await app.register(mcpRoute(opts.db, embed, config));
|
|
123
|
+
await app.register(dashboardRoute(opts.db, config, opts.token, opts.healthState));
|
|
124
|
+
await app.register(dashboardConsolidationRoute(opts.db, opts.token));
|
|
125
|
+
await app.register(dashboardJobsRoute(opts.db, opts.token));
|
|
126
|
+
await app.register(dashboardSearchRoute(opts.db, embed, opts.token));
|
|
127
|
+
await app.register(dashboardApiRoute(opts.token));
|
|
128
|
+
await app.register(memoryToolRoute(opts.db, config));
|
|
129
|
+
await app.register(consolidationRoutes(opts.db));
|
|
130
|
+
await app.register(entitiesRoute(opts.db));
|
|
131
|
+
return app;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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"}
|