@atomicmemory/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE +201 -0
- package/README.md +314 -0
- package/dist/app/bind-ephemeral.d.ts +18 -0
- package/dist/app/bind-ephemeral.js +22 -0
- package/dist/app/cors-headers.d.ts +12 -0
- package/dist/app/cors-headers.js +18 -0
- package/dist/app/create-app.d.ts +25 -0
- package/dist/app/create-app.js +156 -0
- package/dist/app/runtime-config-route-snapshot.d.ts +27 -0
- package/dist/app/runtime-config-route-snapshot.js +27 -0
- package/dist/app/runtime-container.d.ts +281 -0
- package/dist/app/runtime-container.js +297 -0
- package/dist/app/startup-checks.d.ts +28 -0
- package/dist/app/startup-checks.js +45 -0
- package/dist/bin.d.ts +17 -0
- package/dist/bin.js +128 -0
- package/dist/config.d.ts +680 -0
- package/dist/config.js +808 -0
- package/dist/db/agent-trust-repository.d.ts +49 -0
- package/dist/db/agent-trust-repository.js +66 -0
- package/dist/db/belief-edges-repository.d.ts +68 -0
- package/dist/db/belief-edges-repository.js +124 -0
- package/dist/db/claim-repository.d.ts +6 -0
- package/dist/db/claim-repository.js +4 -0
- package/dist/db/contradictions-repository.d.ts +56 -0
- package/dist/db/contradictions-repository.js +88 -0
- package/dist/db/document-chunk-repository.d.ts +48 -0
- package/dist/db/document-chunk-repository.js +145 -0
- package/dist/db/document-chunk-types.d.ts +35 -0
- package/dist/db/document-chunk-types.js +9 -0
- package/dist/db/document-list-cursor.d.ts +45 -0
- package/dist/db/document-list-cursor.js +111 -0
- package/dist/db/document-list-repository.d.ts +103 -0
- package/dist/db/document-list-repository.js +204 -0
- package/dist/db/entity-cards-repository.d.ts +37 -0
- package/dist/db/entity-cards-repository.js +46 -0
- package/dist/db/entity-values-repository.d.ts +26 -0
- package/dist/db/entity-values-repository.js +57 -0
- package/dist/db/link-repository.d.ts +30 -0
- package/dist/db/link-repository.js +54 -0
- package/dist/db/memory-repository.d.ts +163 -0
- package/dist/db/memory-repository.js +232 -0
- package/dist/db/migrate.d.ts +6 -0
- package/dist/db/migrate.js +36 -0
- package/dist/db/mmr.d.ts +14 -0
- package/dist/db/mmr.js +57 -0
- package/dist/db/passport-feed-repository.d.ts +91 -0
- package/dist/db/passport-feed-repository.js +198 -0
- package/dist/db/pg-episode-store.d.ts +19 -0
- package/dist/db/pg-episode-store.js +17 -0
- package/dist/db/pg-link-store.d.ts +17 -0
- package/dist/db/pg-link-store.js +14 -0
- package/dist/db/pg-memory-store.d.ts +68 -0
- package/dist/db/pg-memory-store.js +53 -0
- package/dist/db/pg-recap-store.d.ts +13 -0
- package/dist/db/pg-recap-store.js +19 -0
- package/dist/db/pg-representation-store.d.ts +17 -0
- package/dist/db/pg-representation-store.js +17 -0
- package/dist/db/pg-search-store.d.ts +29 -0
- package/dist/db/pg-search-store.js +47 -0
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +21 -0
- package/dist/db/ppr.d.ts +56 -0
- package/dist/db/ppr.js +178 -0
- package/dist/db/query-helpers.d.ts +44 -0
- package/dist/db/query-helpers.js +60 -0
- package/dist/db/raw-doc-artifact-sync.d.ts +128 -0
- package/dist/db/raw-doc-artifact-sync.js +259 -0
- package/dist/db/raw-document-blob-repository.d.ts +148 -0
- package/dist/db/raw-document-blob-repository.js +300 -0
- package/dist/db/raw-document-repository.d.ts +104 -0
- package/dist/db/raw-document-repository.js +410 -0
- package/dist/db/raw-document-status-repository.d.ts +122 -0
- package/dist/db/raw-document-status-repository.js +183 -0
- package/dist/db/raw-document-types.d.ts +236 -0
- package/dist/db/raw-document-types.js +10 -0
- package/dist/db/raw-storage-reconciliation-repository.d.ts +110 -0
- package/dist/db/raw-storage-reconciliation-repository.js +200 -0
- package/dist/db/reflection-jobs-repository.d.ts +33 -0
- package/dist/db/reflection-jobs-repository.js +48 -0
- package/dist/db/reflections-repository.d.ts +41 -0
- package/dist/db/reflections-repository.js +83 -0
- package/dist/db/repository-claims.d.ts +141 -0
- package/dist/db/repository-claims.js +376 -0
- package/dist/db/repository-deferred-audn.d.ts +33 -0
- package/dist/db/repository-deferred-audn.js +69 -0
- package/dist/db/repository-document-delete.d.ts +53 -0
- package/dist/db/repository-document-delete.js +156 -0
- package/dist/db/repository-entities.d.ts +114 -0
- package/dist/db/repository-entities.js +317 -0
- package/dist/db/repository-entity-attributes.d.ts +41 -0
- package/dist/db/repository-entity-attributes.js +65 -0
- package/dist/db/repository-entity-graph.d.ts +32 -0
- package/dist/db/repository-entity-graph.js +87 -0
- package/dist/db/repository-first-mentions.d.ts +41 -0
- package/dist/db/repository-first-mentions.js +79 -0
- package/dist/db/repository-lessons.d.ts +51 -0
- package/dist/db/repository-lessons.js +90 -0
- package/dist/db/repository-links.d.ts +26 -0
- package/dist/db/repository-links.js +105 -0
- package/dist/db/repository-observation.d.ts +26 -0
- package/dist/db/repository-observation.js +51 -0
- package/dist/db/repository-read.d.ts +56 -0
- package/dist/db/repository-read.js +271 -0
- package/dist/db/repository-recaps.d.ts +59 -0
- package/dist/db/repository-recaps.js +158 -0
- package/dist/db/repository-representations.d.ts +48 -0
- package/dist/db/repository-representations.js +162 -0
- package/dist/db/repository-temporal-state.d.ts +35 -0
- package/dist/db/repository-temporal-state.js +46 -0
- package/dist/db/repository-tll.d.ts +88 -0
- package/dist/db/repository-tll.js +179 -0
- package/dist/db/repository-types.d.ts +313 -0
- package/dist/db/repository-types.js +142 -0
- package/dist/db/repository-user-profiles.d.ts +17 -0
- package/dist/db/repository-user-profiles.js +28 -0
- package/dist/db/repository-vector-search.d.ts +33 -0
- package/dist/db/repository-vector-search.js +373 -0
- package/dist/db/repository-wipe.d.ts +34 -0
- package/dist/db/repository-wipe.js +94 -0
- package/dist/db/repository-write.d.ts +61 -0
- package/dist/db/repository-write.js +279 -0
- package/dist/db/schema.sql +1355 -0
- package/dist/db/storage-artifact-delete-tx.d.ts +56 -0
- package/dist/db/storage-artifact-delete-tx.js +123 -0
- package/dist/db/storage-artifact-providers.d.ts +21 -0
- package/dist/db/storage-artifact-providers.js +21 -0
- package/dist/db/storage-artifact-recovery-repository.d.ts +66 -0
- package/dist/db/storage-artifact-recovery-repository.js +58 -0
- package/dist/db/storage-artifact-repository.d.ts +329 -0
- package/dist/db/storage-artifact-repository.js +497 -0
- package/dist/db/stores.d.ts +220 -0
- package/dist/db/stores.js +12 -0
- package/dist/db/summaries-repository.d.ts +74 -0
- package/dist/db/summaries-repository.js +125 -0
- package/dist/eval/beam-10m-loader.d.ts +98 -0
- package/dist/eval/beam-10m-loader.js +128 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +17 -0
- package/dist/middleware/require-bearer.d.ts +27 -0
- package/dist/middleware/require-bearer.js +60 -0
- package/dist/middleware/validate-response.d.ts +33 -0
- package/dist/middleware/validate-response.js +55 -0
- package/dist/middleware/validate.d.ts +43 -0
- package/dist/middleware/validate.js +85 -0
- package/dist/routes/agents.d.ts +13 -0
- package/dist/routes/agents.js +89 -0
- package/dist/routes/document-response-formatters.d.ts +98 -0
- package/dist/routes/document-response-formatters.js +243 -0
- package/dist/routes/documents.d.ts +74 -0
- package/dist/routes/documents.js +425 -0
- package/dist/routes/memories.d.ts +29 -0
- package/dist/routes/memories.js +725 -0
- package/dist/routes/memory-response-formatters.d.ts +179 -0
- package/dist/routes/memory-response-formatters.js +210 -0
- package/dist/routes/public-raw-storage-metadata.d.ts +54 -0
- package/dist/routes/public-raw-storage-metadata.js +56 -0
- package/dist/routes/reflect.d.ts +14 -0
- package/dist/routes/reflect.js +19 -0
- package/dist/routes/response-schema-map.d.ts +14 -0
- package/dist/routes/response-schema-map.js +69 -0
- package/dist/routes/route-errors.d.ts +12 -0
- package/dist/routes/route-errors.js +30 -0
- package/dist/routes/storage-error-handlers.d.ts +34 -0
- package/dist/routes/storage-error-handlers.js +185 -0
- package/dist/routes/storage-response-formatters.d.ts +44 -0
- package/dist/routes/storage-response-formatters.js +155 -0
- package/dist/routes/storage.d.ts +38 -0
- package/dist/routes/storage.js +369 -0
- package/dist/routes/upstream-provider-errors.d.ts +19 -0
- package/dist/routes/upstream-provider-errors.js +95 -0
- package/dist/schemas/agents.d.ts +79 -0
- package/dist/schemas/agents.js +126 -0
- package/dist/schemas/common.d.ts +110 -0
- package/dist/schemas/common.js +190 -0
- package/dist/schemas/document-list-responses.d.ts +102 -0
- package/dist/schemas/document-list-responses.js +87 -0
- package/dist/schemas/document-list-schemas.d.ts +123 -0
- package/dist/schemas/document-list-schemas.js +174 -0
- package/dist/schemas/document-response-schemas.d.ts +610 -0
- package/dist/schemas/document-response-schemas.js +264 -0
- package/dist/schemas/document-status-envelope.d.ts +48 -0
- package/dist/schemas/document-status-envelope.js +54 -0
- package/dist/schemas/documents.d.ts +292 -0
- package/dist/schemas/documents.js +449 -0
- package/dist/schemas/errors.d.ts +75 -0
- package/dist/schemas/errors.js +105 -0
- package/dist/schemas/memories.d.ts +378 -0
- package/dist/schemas/memories.js +542 -0
- package/dist/schemas/openapi.d.ts +24 -0
- package/dist/schemas/openapi.js +1038 -0
- package/dist/schemas/response-scalars.d.ts +10 -0
- package/dist/schemas/response-scalars.js +10 -0
- package/dist/schemas/responses.d.ts +536 -0
- package/dist/schemas/responses.js +350 -0
- package/dist/schemas/search-response-parts.d.ts +97 -0
- package/dist/schemas/search-response-parts.js +103 -0
- package/dist/schemas/storage-schemas.d.ts +175 -0
- package/dist/schemas/storage-schemas.js +277 -0
- package/dist/schemas/zod-setup.d.ts +15 -0
- package/dist/schemas/zod-setup.js +17 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +57 -0
- package/dist/services/abstract-query-policy.d.ts +13 -0
- package/dist/services/abstract-query-policy.js +50 -0
- package/dist/services/affinity-clustering.d.ts +66 -0
- package/dist/services/affinity-clustering.js +125 -0
- package/dist/services/agentic-retrieval.d.ts +38 -0
- package/dist/services/agentic-retrieval.js +126 -0
- package/dist/services/answer-format.d.ts +56 -0
- package/dist/services/answer-format.js +118 -0
- package/dist/services/answer-rescue.d.ts +72 -0
- package/dist/services/answer-rescue.js +177 -0
- package/dist/services/answer-verifier.d.ts +24 -0
- package/dist/services/answer-verifier.js +73 -0
- package/dist/services/api-retry.d.ts +6 -0
- package/dist/services/api-retry.js +41 -0
- package/dist/services/assistant-turn-filter.d.ts +20 -0
- package/dist/services/assistant-turn-filter.js +69 -0
- package/dist/services/atomicmem-uri.d.ts +33 -0
- package/dist/services/atomicmem-uri.js +86 -0
- package/dist/services/audit-events.d.ts +54 -0
- package/dist/services/audit-events.js +56 -0
- package/dist/services/chunked-extraction.d.ts +21 -0
- package/dist/services/chunked-extraction.js +108 -0
- package/dist/services/claim-slotting.d.ts +27 -0
- package/dist/services/claim-slotting.js +38 -0
- package/dist/services/claude-code-llm.d.ts +19 -0
- package/dist/services/claude-code-llm.js +96 -0
- package/dist/services/composite-dedup.d.ts +50 -0
- package/dist/services/composite-dedup.js +153 -0
- package/dist/services/composite-grouping.d.ts +41 -0
- package/dist/services/composite-grouping.js +111 -0
- package/dist/services/composite-staleness.d.ts +20 -0
- package/dist/services/composite-staleness.js +50 -0
- package/dist/services/conciseness-preference.d.ts +14 -0
- package/dist/services/conciseness-preference.js +42 -0
- package/dist/services/conflict-policy.d.ts +20 -0
- package/dist/services/conflict-policy.js +335 -0
- package/dist/services/consensus-extraction.d.ts +39 -0
- package/dist/services/consensus-extraction.js +147 -0
- package/dist/services/consensus-validation.d.ts +52 -0
- package/dist/services/consensus-validation.js +206 -0
- package/dist/services/consolidation-service.d.ts +60 -0
- package/dist/services/consolidation-service.js +171 -0
- package/dist/services/content-detection.d.ts +18 -0
- package/dist/services/content-detection.js +25 -0
- package/dist/services/contradiction-surfacing.d.ts +62 -0
- package/dist/services/contradiction-surfacing.js +111 -0
- package/dist/services/cost-telemetry.d.ts +39 -0
- package/dist/services/cost-telemetry.js +58 -0
- package/dist/services/counter-evidence.d.ts +34 -0
- package/dist/services/counter-evidence.js +92 -0
- package/dist/services/current-state-ranking.d.ts +21 -0
- package/dist/services/current-state-ranking.js +152 -0
- package/dist/services/deferred-audn.d.ts +47 -0
- package/dist/services/deferred-audn.js +162 -0
- package/dist/services/document-chunker.d.ts +50 -0
- package/dist/services/document-chunker.js +153 -0
- package/dist/services/document-failure-markers.d.ts +91 -0
- package/dist/services/document-failure-markers.js +305 -0
- package/dist/services/document-indexer.d.ts +122 -0
- package/dist/services/document-indexer.js +405 -0
- package/dist/services/document-service.d.ts +245 -0
- package/dist/services/document-service.js +325 -0
- package/dist/services/document-upload-artifact-sync.d.ts +80 -0
- package/dist/services/document-upload-artifact-sync.js +162 -0
- package/dist/services/document-upload-beta2-recovery.d.ts +72 -0
- package/dist/services/document-upload-beta2-recovery.js +94 -0
- package/dist/services/document-upload.d.ts +44 -0
- package/dist/services/document-upload.js +353 -0
- package/dist/services/embedding.d.ts +57 -0
- package/dist/services/embedding.js +416 -0
- package/dist/services/entity-attribute-extractor.d.ts +34 -0
- package/dist/services/entity-attribute-extractor.js +117 -0
- package/dist/services/entity-card-synthesis.d.ts +54 -0
- package/dist/services/entity-card-synthesis.js +92 -0
- package/dist/services/entity-dedup.d.ts +9 -0
- package/dist/services/entity-dedup.js +14 -0
- package/dist/services/entity-graph.d.ts +17 -0
- package/dist/services/entity-graph.js +135 -0
- package/dist/services/entropy-gate.d.ts +52 -0
- package/dist/services/entropy-gate.js +56 -0
- package/dist/services/episode-fetcher.d.ts +47 -0
- package/dist/services/episode-fetcher.js +128 -0
- package/dist/services/event-anchor-facts.d.ts +8 -0
- package/dist/services/event-anchor-facts.js +205 -0
- package/dist/services/event-chain-detector.d.ts +52 -0
- package/dist/services/event-chain-detector.js +83 -0
- package/dist/services/extraction-cache.d.ts +9 -0
- package/dist/services/extraction-cache.js +54 -0
- package/dist/services/extraction-enrichment.d.ts +9 -0
- package/dist/services/extraction-enrichment.js +223 -0
- package/dist/services/extraction.d.ts +69 -0
- package/dist/services/extraction.js +596 -0
- package/dist/services/fact-normalization.d.ts +12 -0
- package/dist/services/fact-normalization.js +248 -0
- package/dist/services/filecoin-observability.d.ts +127 -0
- package/dist/services/filecoin-observability.js +200 -0
- package/dist/services/first-mention-service.d.ts +76 -0
- package/dist/services/first-mention-service.js +186 -0
- package/dist/services/hierarchical-retrieval.d.ts +49 -0
- package/dist/services/hierarchical-retrieval.js +50 -0
- package/dist/services/ingest-fact-pipeline.d.ts +32 -0
- package/dist/services/ingest-fact-pipeline.js +212 -0
- package/dist/services/ingest-post-write.d.ts +50 -0
- package/dist/services/ingest-post-write.js +117 -0
- package/dist/services/ingest-trace.d.ts +32 -0
- package/dist/services/ingest-trace.js +60 -0
- package/dist/services/input-sanitizer.d.ts +41 -0
- package/dist/services/input-sanitizer.js +135 -0
- package/dist/services/iterative-retrieval.d.ts +26 -0
- package/dist/services/iterative-retrieval.js +139 -0
- package/dist/services/keyword-expansion.d.ts +10 -0
- package/dist/services/keyword-expansion.js +26 -0
- package/dist/services/lesson-service.d.ts +68 -0
- package/dist/services/lesson-service.js +178 -0
- package/dist/services/literal-extractor.d.ts +16 -0
- package/dist/services/literal-extractor.js +74 -0
- package/dist/services/literal-list-protection.d.ts +17 -0
- package/dist/services/literal-list-protection.js +134 -0
- package/dist/services/literal-query-expansion.d.ts +20 -0
- package/dist/services/literal-query-expansion.js +181 -0
- package/dist/services/llm.d.ts +61 -0
- package/dist/services/llm.js +265 -0
- package/dist/services/memcell-projection.d.ts +17 -0
- package/dist/services/memcell-projection.js +41 -0
- package/dist/services/memory-audn.d.ts +43 -0
- package/dist/services/memory-audn.js +419 -0
- package/dist/services/memory-crud.d.ts +93 -0
- package/dist/services/memory-crud.js +255 -0
- package/dist/services/memory-ingest.d.ts +21 -0
- package/dist/services/memory-ingest.js +249 -0
- package/dist/services/memory-lifecycle.d.ts +75 -0
- package/dist/services/memory-lifecycle.js +108 -0
- package/dist/services/memory-lineage.d.ts +181 -0
- package/dist/services/memory-lineage.js +232 -0
- package/dist/services/memory-network.d.ts +40 -0
- package/dist/services/memory-network.js +75 -0
- package/dist/services/memory-search-types.d.ts +25 -0
- package/dist/services/memory-search-types.js +10 -0
- package/dist/services/memory-search.d.ts +48 -0
- package/dist/services/memory-search.js +505 -0
- package/dist/services/memory-service-types.d.ts +371 -0
- package/dist/services/memory-service-types.js +8 -0
- package/dist/services/memory-service.d.ts +152 -0
- package/dist/services/memory-service.js +225 -0
- package/dist/services/memory-storage.d.ts +33 -0
- package/dist/services/memory-storage.js +328 -0
- package/dist/services/msr-aggregator.d.ts +38 -0
- package/dist/services/msr-aggregator.js +97 -0
- package/dist/services/msr-detector.d.ts +35 -0
- package/dist/services/msr-detector.js +65 -0
- package/dist/services/namespace-retrieval.d.ts +60 -0
- package/dist/services/namespace-retrieval.js +180 -0
- package/dist/services/observation-date-extraction.d.ts +12 -0
- package/dist/services/observation-date-extraction.js +50 -0
- package/dist/services/observation-service.d.ts +27 -0
- package/dist/services/observation-service.js +84 -0
- package/dist/services/packaging-observability.d.ts +29 -0
- package/dist/services/packaging-observability.js +146 -0
- package/dist/services/query-expansion.d.ts +83 -0
- package/dist/services/query-expansion.js +242 -0
- package/dist/services/query-keyword-matches.d.ts +6 -0
- package/dist/services/query-keyword-matches.js +56 -0
- package/dist/services/query-term-visibility.d.ts +28 -0
- package/dist/services/query-term-visibility.js +100 -0
- package/dist/services/quick-extraction.d.ts +25 -0
- package/dist/services/quick-extraction.js +431 -0
- package/dist/services/quoted-entity-extraction.d.ts +10 -0
- package/dist/services/quoted-entity-extraction.js +161 -0
- package/dist/services/raw-storage-reconciler-backoff.d.ts +8 -0
- package/dist/services/raw-storage-reconciler-backoff.js +14 -0
- package/dist/services/raw-storage-reconciler-scheduler.d.ts +29 -0
- package/dist/services/raw-storage-reconciler-scheduler.js +43 -0
- package/dist/services/raw-storage-reconciler.d.ts +71 -0
- package/dist/services/raw-storage-reconciler.js +278 -0
- package/dist/services/recap-builder.d.ts +49 -0
- package/dist/services/recap-builder.js +157 -0
- package/dist/services/reflect-jobs.d.ts +23 -0
- package/dist/services/reflect-jobs.js +36 -0
- package/dist/services/reflect-prompts.d.ts +71 -0
- package/dist/services/reflect-prompts.js +99 -0
- package/dist/services/reflect-retrieval.d.ts +33 -0
- package/dist/services/reflect-retrieval.js +30 -0
- package/dist/services/reflect.d.ts +49 -0
- package/dist/services/reflect.js +84 -0
- package/dist/services/relative-temporal.d.ts +14 -0
- package/dist/services/relative-temporal.js +163 -0
- package/dist/services/relevance-policy.d.ts +37 -0
- package/dist/services/relevance-policy.js +109 -0
- package/dist/services/rerank.d.ts +32 -0
- package/dist/services/rerank.js +118 -0
- package/dist/services/reranker.d.ts +20 -0
- package/dist/services/reranker.js +99 -0
- package/dist/services/retrieval-channel-rules.d.ts +34 -0
- package/dist/services/retrieval-channel-rules.js +41 -0
- package/dist/services/retrieval-config-overlay.d.ts +36 -0
- package/dist/services/retrieval-config-overlay.js +44 -0
- package/dist/services/retrieval-format.d.ts +119 -0
- package/dist/services/retrieval-format.js +559 -0
- package/dist/services/retrieval-policy.d.ts +69 -0
- package/dist/services/retrieval-policy.js +275 -0
- package/dist/services/retrieval-profiles.d.ts +37 -0
- package/dist/services/retrieval-profiles.js +90 -0
- package/dist/services/retrieval-side-effects.d.ts +14 -0
- package/dist/services/retrieval-side-effects.js +26 -0
- package/dist/services/retrieval-trace.d.ts +108 -0
- package/dist/services/retrieval-trace.js +147 -0
- package/dist/services/rrf-fusion.d.ts +18 -0
- package/dist/services/rrf-fusion.js +34 -0
- package/dist/services/search-pipeline.d.ts +71 -0
- package/dist/services/search-pipeline.js +788 -0
- package/dist/services/session-date.d.ts +20 -0
- package/dist/services/session-date.js +61 -0
- package/dist/services/session-packaging.d.ts +53 -0
- package/dist/services/session-packaging.js +182 -0
- package/dist/services/session-summary-generator.d.ts +53 -0
- package/dist/services/session-summary-generator.js +134 -0
- package/dist/services/specialists/cr-specialist.d.ts +52 -0
- package/dist/services/specialists/cr-specialist.js +121 -0
- package/dist/services/specialists/dispatch.d.ts +53 -0
- package/dist/services/specialists/dispatch.js +102 -0
- package/dist/services/specialists/ie-ku-specialist.d.ts +37 -0
- package/dist/services/specialists/ie-ku-specialist.js +63 -0
- package/dist/services/specialists/msr-specialist.d.ts +61 -0
- package/dist/services/specialists/msr-specialist.js +162 -0
- package/dist/services/specialists/tr-specialist.d.ts +37 -0
- package/dist/services/specialists/tr-specialist.js +146 -0
- package/dist/services/storage-key-prefix.d.ts +42 -0
- package/dist/services/storage-key-prefix.js +45 -0
- package/dist/services/storage-put-recovery.d.ts +71 -0
- package/dist/services/storage-put-recovery.js +269 -0
- package/dist/services/storage-service-errors.d.ts +124 -0
- package/dist/services/storage-service-errors.js +189 -0
- package/dist/services/storage-service.d.ts +176 -0
- package/dist/services/storage-service.js +423 -0
- package/dist/services/subject-aware-ranking.d.ts +19 -0
- package/dist/services/subject-aware-ranking.js +161 -0
- package/dist/services/supplemental-extraction.d.ts +7 -0
- package/dist/services/supplemental-extraction.js +116 -0
- package/dist/services/tbc-execution.d.ts +49 -0
- package/dist/services/tbc-execution.js +284 -0
- package/dist/services/temporal-classifier.d.ts +56 -0
- package/dist/services/temporal-classifier.js +94 -0
- package/dist/services/temporal-endpoint-evidence.d.ts +12 -0
- package/dist/services/temporal-endpoint-evidence.js +313 -0
- package/dist/services/temporal-fingerprint.d.ts +6 -0
- package/dist/services/temporal-fingerprint.js +12 -0
- package/dist/services/temporal-format.d.ts +9 -0
- package/dist/services/temporal-format.js +21 -0
- package/dist/services/temporal-intent.d.ts +39 -0
- package/dist/services/temporal-intent.js +78 -0
- package/dist/services/temporal-query-constraints.d.ts +16 -0
- package/dist/services/temporal-query-constraints.js +107 -0
- package/dist/services/temporal-query-expansion.d.ts +14 -0
- package/dist/services/temporal-query-expansion.js +131 -0
- package/dist/services/temporal-rerank.d.ts +22 -0
- package/dist/services/temporal-rerank.js +47 -0
- package/dist/services/temporal-result-protection.d.ts +7 -0
- package/dist/services/temporal-result-protection.js +60 -0
- package/dist/services/temporal-state-write.d.ts +57 -0
- package/dist/services/temporal-state-write.js +45 -0
- package/dist/services/tiered-context.d.ts +87 -0
- package/dist/services/tiered-context.js +214 -0
- package/dist/services/tiered-loading.d.ts +88 -0
- package/dist/services/tiered-loading.js +263 -0
- package/dist/services/timeline-pack.d.ts +36 -0
- package/dist/services/timeline-pack.js +50 -0
- package/dist/services/timing.d.ts +13 -0
- package/dist/services/timing.js +72 -0
- package/dist/services/tll-augmentation.d.ts +20 -0
- package/dist/services/tll-augmentation.js +125 -0
- package/dist/services/tll-retrieval.d.ts +55 -0
- package/dist/services/tll-retrieval.js +101 -0
- package/dist/services/topic-abstraction.d.ts +36 -0
- package/dist/services/topic-abstraction.js +105 -0
- package/dist/services/trust-scoring.d.ts +43 -0
- package/dist/services/trust-scoring.js +89 -0
- package/dist/services/typed-belief-calculus.d.ts +126 -0
- package/dist/services/typed-belief-calculus.js +204 -0
- package/dist/services/upload-config.d.ts +34 -0
- package/dist/services/upload-config.js +23 -0
- package/dist/services/upload-decision.d.ts +65 -0
- package/dist/services/upload-decision.js +98 -0
- package/dist/services/upload-helpers.d.ts +107 -0
- package/dist/services/upload-helpers.js +148 -0
- package/dist/services/user-profile-builder.d.ts +22 -0
- package/dist/services/user-profile-builder.js +109 -0
- package/dist/services/voyage-embedding.d.ts +22 -0
- package/dist/services/voyage-embedding.js +77 -0
- package/dist/services/write-security.d.ts +31 -0
- package/dist/services/write-security.js +64 -0
- package/dist/storage/artifact-public-redaction.d.ts +34 -0
- package/dist/storage/artifact-public-redaction.js +83 -0
- package/dist/storage/cleanup.d.ts +103 -0
- package/dist/storage/cleanup.js +138 -0
- package/dist/storage/codec-factory.d.ts +17 -0
- package/dist/storage/codec-factory.js +33 -0
- package/dist/storage/codecs/aes-gcm-codec.d.ts +44 -0
- package/dist/storage/codecs/aes-gcm-codec.js +108 -0
- package/dist/storage/codecs/noop-codec.d.ts +16 -0
- package/dist/storage/codecs/noop-codec.js +23 -0
- package/dist/storage/factory.d.ts +44 -0
- package/dist/storage/factory.js +99 -0
- package/dist/storage/filecoin-cid-validation.d.ts +82 -0
- package/dist/storage/filecoin-cid-validation.js +122 -0
- package/dist/storage/filecoin-public-metadata.d.ts +73 -0
- package/dist/storage/filecoin-public-metadata.js +110 -0
- package/dist/storage/local-fs-store.d.ts +39 -0
- package/dist/storage/local-fs-store.js +145 -0
- package/dist/storage/pointer-uri-allowlist.d.ts +38 -0
- package/dist/storage/pointer-uri-allowlist.js +70 -0
- package/dist/storage/provider-metadata-projection.d.ts +27 -0
- package/dist/storage/provider-metadata-projection.js +68 -0
- package/dist/storage/providers/filecoin/backend.d.ts +42 -0
- package/dist/storage/providers/filecoin/backend.js +250 -0
- package/dist/storage/providers/filecoin/config.d.ts +70 -0
- package/dist/storage/providers/filecoin/config.js +275 -0
- package/dist/storage/providers/filecoin/errors.d.ts +45 -0
- package/dist/storage/providers/filecoin/errors.js +56 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.d.ts +78 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.js +155 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.d.ts +92 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.js +199 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.d.ts +58 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.js +103 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.d.ts +30 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.js +53 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.d.ts +111 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.js +87 -0
- package/dist/storage/providers/filecoin/hints.d.ts +71 -0
- package/dist/storage/providers/filecoin/hints.js +123 -0
- package/dist/storage/providers/filecoin/index.d.ts +51 -0
- package/dist/storage/providers/filecoin/index.js +103 -0
- package/dist/storage/providers/filecoin/ipfs-cid.d.ts +50 -0
- package/dist/storage/providers/filecoin/ipfs-cid.js +64 -0
- package/dist/storage/providers/filecoin/metadata.d.ts +72 -0
- package/dist/storage/providers/filecoin/metadata.js +137 -0
- package/dist/storage/providers/filecoin/piece-cid.d.ts +48 -0
- package/dist/storage/providers/filecoin/piece-cid.js +57 -0
- package/dist/storage/providers/filecoin/provider-client.d.ts +234 -0
- package/dist/storage/providers/filecoin/provider-client.js +27 -0
- package/dist/storage/providers/filecoin/readiness.d.ts +62 -0
- package/dist/storage/providers/filecoin/readiness.js +85 -0
- package/dist/storage/providers/filecoin/retriever.d.ts +82 -0
- package/dist/storage/providers/filecoin/retriever.js +63 -0
- package/dist/storage/providers/filecoin/skeleton-client.d.ts +36 -0
- package/dist/storage/providers/filecoin/skeleton-client.js +55 -0
- package/dist/storage/providers/filecoin/synapse-client.d.ts +169 -0
- package/dist/storage/providers/filecoin/synapse-client.js +343 -0
- package/dist/storage/providers/filecoin/synapse-construction.d.ts +26 -0
- package/dist/storage/providers/filecoin/synapse-construction.js +47 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.d.ts +23 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.js +49 -0
- package/dist/storage/providers/filecoin/synapse-readiness.d.ts +37 -0
- package/dist/storage/providers/filecoin/synapse-readiness.js +231 -0
- package/dist/storage/providers/filecoin/uri.d.ts +49 -0
- package/dist/storage/providers/filecoin/uri.js +84 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.d.ts +77 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.js +196 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.d.ts +54 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.js +81 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.d.ts +71 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.js +94 -0
- package/dist/storage/raw-content-codec.d.ts +89 -0
- package/dist/storage/raw-content-codec.js +47 -0
- package/dist/storage/raw-content-store-backend-adapter.d.ts +28 -0
- package/dist/storage/raw-content-store-backend-adapter.js +67 -0
- package/dist/storage/raw-content-store.d.ts +228 -0
- package/dist/storage/raw-content-store.js +27 -0
- package/dist/storage/s3-store.d.ts +42 -0
- package/dist/storage/s3-store.js +181 -0
- package/dist/storage/storage-backend-registry.d.ts +58 -0
- package/dist/storage/storage-backend-registry.js +56 -0
- package/dist/storage/storage-backend.d.ts +82 -0
- package/dist/storage/storage-backend.js +14 -0
- package/dist/storage/storage-capabilities.d.ts +56 -0
- package/dist/storage/storage-capabilities.js +170 -0
- package/dist/storage/store-registry.d.ts +67 -0
- package/dist/storage/store-registry.js +77 -0
- package/dist/vector-math.d.ts +15 -0
- package/dist/vector-math.js +31 -0
- package/dist/xml-escape.d.ts +5 -0
- package/dist/xml-escape.js +7 -0
- package/openapi.json +15395 -0
- package/openapi.yaml +10794 -0
- package/package.json +119 -0
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search and link pipeline — orchestrates retrieval (search → repair loop →
|
|
3
|
+
* expansion → MMR → trace) and post-ingest link generation.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from MemoryService to keep that file focused on ingest orchestration.
|
|
6
|
+
*/
|
|
7
|
+
import { config } from '../config.js';
|
|
8
|
+
import { runHierarchicalArm } from './hierarchical-retrieval.js';
|
|
9
|
+
import { embedText } from './embedding.js';
|
|
10
|
+
import { rewriteQuery } from './extraction.js';
|
|
11
|
+
import { applyRankingEligibility, resolveRerankDepth, shouldRunRepairLoop, shouldAcceptRepair, } from './retrieval-policy.js';
|
|
12
|
+
import { applyMMR } from '../db/mmr.js';
|
|
13
|
+
import { personalizedPageRank } from '../db/ppr.js';
|
|
14
|
+
import { TraceCollector } from './retrieval-trace.js';
|
|
15
|
+
import { isInScope } from './namespace-retrieval.js';
|
|
16
|
+
import { expandQueryViaEntities, augmentQueryWithEntities, coRetrieveByEntityNames } from './query-expansion.js';
|
|
17
|
+
import { rerankCandidates } from './reranker.js';
|
|
18
|
+
import { shouldUseAbstractHybridFallback } from './abstract-query-policy.js';
|
|
19
|
+
import { applyAgenticRetrieval } from './agentic-retrieval.js';
|
|
20
|
+
import { timed } from './timing.js';
|
|
21
|
+
import { expandTemporalQuery } from './temporal-query-expansion.js';
|
|
22
|
+
import { preserveProtectedResults } from './temporal-result-protection.js';
|
|
23
|
+
import { buildTemporalFingerprint } from './temporal-fingerprint.js';
|
|
24
|
+
import { expandLiteralQuery, isLiteralDetailQuery } from './literal-query-expansion.js';
|
|
25
|
+
import { applySubjectAwareRanking, expandSubjectQuery } from './subject-aware-ranking.js';
|
|
26
|
+
import { DEFAULT_RRF_K, weightedRRF } from './rrf-fusion.js';
|
|
27
|
+
import { applyIterativeRetrieval } from './iterative-retrieval.js';
|
|
28
|
+
import { applyCurrentStateRanking } from './current-state-ranking.js';
|
|
29
|
+
import { applyConcisenessPenalty } from './conciseness-preference.js';
|
|
30
|
+
import { protectLiteralListAnswerCandidates } from './literal-list-protection.js';
|
|
31
|
+
import { applyTemporalQueryConstraints } from './temporal-query-constraints.js';
|
|
32
|
+
import { llmRerank, RerankerError } from './rerank.js';
|
|
33
|
+
import { expandWithCounterEvidence } from './counter-evidence.js';
|
|
34
|
+
import { detectEventChains } from './event-chain-detector.js';
|
|
35
|
+
import { fetchReflectionsForQuery } from './reflect-retrieval.js';
|
|
36
|
+
import { classifyQuestion } from './answer-format.js';
|
|
37
|
+
const TEMPORAL_NEIGHBOR_WINDOW_MINUTES = 30;
|
|
38
|
+
const SEMANTIC_RRF_WEIGHT = 1.2;
|
|
39
|
+
const ENTITY_RRF_WEIGHT = 1.3;
|
|
40
|
+
// Sprint 4 iter 3: keyword arm weight comes from runtime config (env
|
|
41
|
+
// KEYWORD_RRF_WEIGHT, default 1.0). Boosts BM25/keyword signal when the
|
|
42
|
+
// query asks for specific named facts ("how many X", "what is Y").
|
|
43
|
+
// Typical boost 1.5–2.0; module-scoped const re-read at request time
|
|
44
|
+
// via the function below so tests can flip the singleton.
|
|
45
|
+
function keywordRrfWeight() {
|
|
46
|
+
return config.keywordRrfWeight ?? 1.0;
|
|
47
|
+
}
|
|
48
|
+
// Hierarchical arm: surfaces atomic facts via conv→session summary chain.
|
|
49
|
+
// Weighted slightly above semantic on the assumption that an ID present in
|
|
50
|
+
// BOTH the hierarchical summary chain AND the semantic top-k is a higher-
|
|
51
|
+
// confidence retrieval signal than semantic alone.
|
|
52
|
+
const HIERARCHICAL_RRF_WEIGHT = 1.4;
|
|
53
|
+
// Topic-abstraction arm (Sprint 3 EO experiment): surfaces facts whose
|
|
54
|
+
// LLM-generated 3-7 word conceptual topic embeds close to the query. Useful
|
|
55
|
+
// for queries that want abstraction-level material (event ordering, multi-
|
|
56
|
+
// session summarization). Weighted comparable to semantic — the topic embed
|
|
57
|
+
// is a derived signal and shouldn't dominate the raw fact match.
|
|
58
|
+
const TOPIC_RRF_WEIGHT = 1.15;
|
|
59
|
+
const TOPIC_CHANNEL_LIMIT_MULTIPLIER = 2;
|
|
60
|
+
// Recap arm (Sprint 3 v1, cross-session synthesis): surfaces pre-computed
|
|
61
|
+
// narratives that already weave together N memories on a topic. Weighted
|
|
62
|
+
// higher than semantic because a single Recap match represents N facts.
|
|
63
|
+
const RECAP_RRF_WEIGHT = 1.5;
|
|
64
|
+
const RECAP_CHANNEL_LIMIT = 4;
|
|
65
|
+
/**
|
|
66
|
+
* Decide whether to auto-skip cross-encoder reranking.
|
|
67
|
+
* Skip when the top vector result is high-confidence and well-separated
|
|
68
|
+
* from the runner-up — reranking rarely changes the ranking in this case.
|
|
69
|
+
* Thresholds are configurable via RERANK_SKIP_TOP_SIMILARITY (default 0.85)
|
|
70
|
+
* and RERANK_SKIP_MIN_GAP (default 0.05). Saves ~150ms per query on CPU.
|
|
71
|
+
*/
|
|
72
|
+
function shouldAutoSkipReranking(results, policyConfig = config) {
|
|
73
|
+
if (results.length < 2)
|
|
74
|
+
return true;
|
|
75
|
+
const topSim = readNormalizedSimilarity(results[0]);
|
|
76
|
+
const secondSim = readNormalizedSimilarity(results[1]);
|
|
77
|
+
return topSim >= policyConfig.rerankSkipTopSimilarity
|
|
78
|
+
&& (topSim - secondSim) >= policyConfig.rerankSkipMinGap;
|
|
79
|
+
}
|
|
80
|
+
function readNormalizedSimilarity(result) {
|
|
81
|
+
const similarity = result?.semantic_similarity ?? result?.similarity ?? 0;
|
|
82
|
+
return Number.isFinite(similarity) ? similarity : 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Core search pipeline implementation with explicit trace collection.
|
|
86
|
+
*/
|
|
87
|
+
export async function runSearchPipelineWithTrace(stores, userId, query, limit, sourceSite, referenceTime, options = {}) {
|
|
88
|
+
const trace = new TraceCollector(query, userId);
|
|
89
|
+
const policyConfig = options.runtimeConfig ?? config;
|
|
90
|
+
const mmrPoolMultiplier = policyConfig.mmrEnabled ? 3 : 1;
|
|
91
|
+
const candidateDepth = resolveRerankDepth(limit, policyConfig) * mmrPoolMultiplier;
|
|
92
|
+
// Phase 1: Embed the raw query to use for entity matching
|
|
93
|
+
const rawQueryEmbedding = await timed('search.embed', () => embedText(query, 'query'));
|
|
94
|
+
// Phase 2: Entity-grounded query augmentation (zero-LLM)
|
|
95
|
+
const augmentation = await timed('search.augmentation', () => applyQueryAugmentation(stores, userId, query, rawQueryEmbedding, trace, policyConfig));
|
|
96
|
+
const queryEmbedding = augmentation.augmentedEmbedding;
|
|
97
|
+
const searchQuery = augmentation.searchQuery;
|
|
98
|
+
const initialResults = await timed('search.vector', () => runInitialRetrieval(stores, userId, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, options.searchStrategy, policyConfig));
|
|
99
|
+
const seededResults = await timed('search.hybrid-fallback', () => maybeApplyAbstractHybridFallback(stores, userId, query, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, options.retrievalMode, options.searchStrategy, initialResults, trace, policyConfig));
|
|
100
|
+
console.log(`[search] Query: "${query}", Results: ${seededResults.length}`);
|
|
101
|
+
trace.stage('initial', seededResults, {
|
|
102
|
+
candidateDepth,
|
|
103
|
+
hybrid: policyConfig.hybridSearchEnabled,
|
|
104
|
+
augmentation: {
|
|
105
|
+
searchQuery,
|
|
106
|
+
matched: searchQuery !== query,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
// Entity name co-retrieval
|
|
110
|
+
const withCoRetrieval = await timed('search.co-retrieval', () => applyEntityNameCoRetrieval(stores, userId, query, queryEmbedding, seededResults, candidateDepth, trace, policyConfig));
|
|
111
|
+
const withSubjectExpansion = await timed('search.subject-query-expansion', () => applySubjectQueryExpansion(stores, userId, query, queryEmbedding, withCoRetrieval, candidateDepth, trace));
|
|
112
|
+
const withLiteralExpansion = await timed('search.literal-query-expansion', () => applyLiteralQueryExpansion(stores, userId, query, queryEmbedding, withSubjectExpansion, candidateDepth, trace));
|
|
113
|
+
const temporalExpansion = await timed('search.temporal-query-expansion', () => applyTemporalQueryExpansion(stores, userId, query, queryEmbedding, withLiteralExpansion, candidateDepth, referenceTime, trace));
|
|
114
|
+
// Query expansion
|
|
115
|
+
const withExpansion = await timed('search.query-expansion', () => applyQueryExpansion(stores, userId, query, queryEmbedding, temporalExpansion.memories, candidateDepth, trace, policyConfig));
|
|
116
|
+
const repaired = options.skipRepairLoop
|
|
117
|
+
? { memories: withExpansion, queryText: searchQuery }
|
|
118
|
+
: await timed('search.repair-loop', () => applyRepairLoop(stores, query, queryEmbedding, withExpansion, candidateDepth, userId, sourceSite, referenceTime, trace, policyConfig, options.searchStrategy, temporalExpansion.temporalAnchorFingerprints));
|
|
119
|
+
const iterated = await timed('search.iterative-retrieval', async () => {
|
|
120
|
+
if (!policyConfig.iterativeRetrievalEnabled)
|
|
121
|
+
return repaired.memories;
|
|
122
|
+
const iterative = await applyIterativeRetrieval(stores.search, userId, query, queryEmbedding, repaired.memories, candidateDepth, sourceSite, referenceTime);
|
|
123
|
+
if (iterative.triggered) {
|
|
124
|
+
trace.stage('iterative-retrieval', iterative.memories, {
|
|
125
|
+
estimatedFactCount: iterative.estimatedFactCount,
|
|
126
|
+
seedIds: iterative.seedIds,
|
|
127
|
+
reason: iterative.reason,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return iterative.memories;
|
|
131
|
+
});
|
|
132
|
+
// Agentic multi-round retrieval
|
|
133
|
+
const results = await timed('search.agentic-retrieval', async () => {
|
|
134
|
+
if (!policyConfig.agenticRetrievalEnabled)
|
|
135
|
+
return iterated;
|
|
136
|
+
const agenticResult = await applyAgenticRetrieval(stores.search, userId, query, iterated, candidateDepth, sourceSite, referenceTime, policyConfig);
|
|
137
|
+
if (agenticResult.triggered) {
|
|
138
|
+
trace.stage('agentic-retrieval', agenticResult.memories, {
|
|
139
|
+
subQueries: agenticResult.subQueries,
|
|
140
|
+
reason: agenticResult.reason,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return agenticResult.memories;
|
|
144
|
+
});
|
|
145
|
+
const selected = await timed('search.expansion-reranking', () => applyExpansionAndReranking(stores, userId, searchQuery, results, queryEmbedding, limit, sourceSite, referenceTime, temporalExpansion.temporalAnchorFingerprints, trace, options.skipReranking, policyConfig));
|
|
146
|
+
const namespaceScope = options.namespaceScope ?? null;
|
|
147
|
+
trace.setRetrievalSummary({
|
|
148
|
+
candidateIds: selected.map((result) => result.id),
|
|
149
|
+
candidateCount: selected.length,
|
|
150
|
+
queryText: repaired.queryText,
|
|
151
|
+
skipRepair: options.skipRepairLoop ?? false,
|
|
152
|
+
});
|
|
153
|
+
if (namespaceScope) {
|
|
154
|
+
trace.event('namespace-filtering', { scope: namespaceScope });
|
|
155
|
+
}
|
|
156
|
+
const filtered = applyNamespaceScopeFilter(selected, namespaceScope, trace);
|
|
157
|
+
const chainResult = detectEventChains({
|
|
158
|
+
candidates: filtered.map((m) => ({
|
|
159
|
+
id: m.id,
|
|
160
|
+
text: m.content,
|
|
161
|
+
observedAt: m.observed_at ?? m.created_at,
|
|
162
|
+
entityIds: m.namespace ? [m.namespace] : [],
|
|
163
|
+
})),
|
|
164
|
+
minMembers: 3,
|
|
165
|
+
minDistinctDates: 3,
|
|
166
|
+
});
|
|
167
|
+
const questionType = classifyQuestion(query);
|
|
168
|
+
const reflections = await fetchReflectionsForQuery({
|
|
169
|
+
reflections: stores.reflections ?? { findSimilar: async () => [] },
|
|
170
|
+
embed: (text) => embedText(text, 'query'),
|
|
171
|
+
topK: policyConfig.reflectRetrievalTopK,
|
|
172
|
+
enabled: policyConfig.reflectEnabled,
|
|
173
|
+
}, userId, query, questionType);
|
|
174
|
+
return { filtered, trace, queryEmbedding: rawQueryEmbedding, chainResult, reflections, questionType };
|
|
175
|
+
}
|
|
176
|
+
function applyNamespaceScopeFilter(selected, namespaceScope, trace) {
|
|
177
|
+
if (!namespaceScope)
|
|
178
|
+
return selected;
|
|
179
|
+
const decisions = selected.map((result) => ({
|
|
180
|
+
id: result.id,
|
|
181
|
+
namespace: result.namespace ?? null,
|
|
182
|
+
sourceSite: result.source_site,
|
|
183
|
+
decision: isInScope(result.namespace, namespaceScope) ? 'kept' : 'filtered',
|
|
184
|
+
}));
|
|
185
|
+
const filtered = selected.filter((result) => isInScope(result.namespace, namespaceScope));
|
|
186
|
+
trace.stage('namespace-filter', filtered, {
|
|
187
|
+
scope: namespaceScope,
|
|
188
|
+
removedIds: decisions.filter((decision) => decision.decision === 'filtered').map((decision) => decision.id),
|
|
189
|
+
decisions,
|
|
190
|
+
});
|
|
191
|
+
return filtered;
|
|
192
|
+
}
|
|
193
|
+
async function runInitialRetrieval(stores, userId, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, searchStrategy = 'memory', policyConfig = config) {
|
|
194
|
+
if (searchStrategy === 'fact-hybrid') {
|
|
195
|
+
return stores.search.searchAtomicFactsHybrid(userId, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime);
|
|
196
|
+
}
|
|
197
|
+
return runMemoryRrfRetrieval(stores, userId, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, policyConfig.hybridSearchEnabled, policyConfig);
|
|
198
|
+
}
|
|
199
|
+
async function maybeApplyAbstractHybridFallback(stores, userId, rawQuery, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, retrievalMode, searchStrategy, initialResults, trace, policyConfig = config) {
|
|
200
|
+
if (searchStrategy === 'fact-hybrid')
|
|
201
|
+
return initialResults;
|
|
202
|
+
if (policyConfig.hybridSearchEnabled || policyConfig.entityGraphEnabled)
|
|
203
|
+
return initialResults;
|
|
204
|
+
if (!shouldUseAbstractHybridFallback(retrievalMode, rawQuery, initialResults.length)) {
|
|
205
|
+
return initialResults;
|
|
206
|
+
}
|
|
207
|
+
const fallbackResults = await runMemoryRrfRetrieval(stores, userId, searchQuery, queryEmbedding, candidateDepth, sourceSite, referenceTime, true, policyConfig);
|
|
208
|
+
trace.stage('abstract-hybrid-fallback', fallbackResults, { candidateDepth });
|
|
209
|
+
return fallbackResults;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Run the repair loop: rewrite the query and merge results if improvement is detected.
|
|
213
|
+
*/
|
|
214
|
+
async function applyRepairLoop(stores, query, queryEmbedding, initialResults, candidateDepth, userId, sourceSite, referenceTime, trace, policyConfig, searchStrategy = 'memory', protectedIds = []) {
|
|
215
|
+
if (!shouldRunRepairLoop(query, initialResults, policyConfig)) {
|
|
216
|
+
return { memories: initialResults, queryText: query };
|
|
217
|
+
}
|
|
218
|
+
const rewrittenQuery = await rewriteQuery(query);
|
|
219
|
+
if (rewrittenQuery === query) {
|
|
220
|
+
trace.stage('repair-skipped', initialResults, { reason: 'rewrite-unchanged' });
|
|
221
|
+
return { memories: initialResults, queryText: query };
|
|
222
|
+
}
|
|
223
|
+
const rewrittenEmbedding = await embedText(rewrittenQuery, 'query');
|
|
224
|
+
const repairedResults = searchStrategy === 'fact-hybrid'
|
|
225
|
+
? await stores.search.searchAtomicFactsHybrid(userId, rewrittenQuery, rewrittenEmbedding, candidateDepth, sourceSite, referenceTime)
|
|
226
|
+
: await runMemoryRrfRetrieval(stores, userId, rewrittenQuery, rewrittenEmbedding, candidateDepth, sourceSite, referenceTime, policyConfig.hybridSearchEnabled, policyConfig);
|
|
227
|
+
const decision = shouldAcceptRepair(initialResults, repairedResults, policyConfig);
|
|
228
|
+
if (decision.accepted) {
|
|
229
|
+
const mergedPool = mergeStageResults(initialResults, repairedResults, initialResults.length + repairedResults.length, policyConfig.retrievalProfileSettings.repairPrimaryWeight, policyConfig.retrievalProfileSettings.repairRewriteWeight);
|
|
230
|
+
const merged = preserveProtectedResults(mergedPool.slice(0, candidateDepth), mergedPool, protectedIds, candidateDepth);
|
|
231
|
+
trace.stage('repair-accepted', merged, {
|
|
232
|
+
rewrittenQuery,
|
|
233
|
+
reason: decision.reason,
|
|
234
|
+
simDelta: decision.simDelta,
|
|
235
|
+
});
|
|
236
|
+
return { memories: merged, queryText: rewrittenQuery };
|
|
237
|
+
}
|
|
238
|
+
trace.stage('repair-rejected', initialResults, {
|
|
239
|
+
rewrittenQuery,
|
|
240
|
+
reason: decision.reason,
|
|
241
|
+
simDelta: decision.simDelta,
|
|
242
|
+
});
|
|
243
|
+
return { memories: initialResults, queryText: query };
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Run LLM-based query expansion: extract entity names and concepts from the
|
|
247
|
+
* query, look them up in the entity graph, traverse relations, and merge
|
|
248
|
+
* bridging memories into the candidate pool.
|
|
249
|
+
*/
|
|
250
|
+
async function applyQueryExpansion(stores, userId, query, queryEmbedding, initialResults, candidateDepth, trace, policyConfig = config) {
|
|
251
|
+
if (!policyConfig.queryExpansionEnabled || !policyConfig.entityGraphEnabled || !stores.entity) {
|
|
252
|
+
return initialResults;
|
|
253
|
+
}
|
|
254
|
+
const excludeIds = new Set(initialResults.map((r) => r.id));
|
|
255
|
+
const { memories, expansion } = await expandQueryViaEntities(stores.entity, stores.search, userId, query, queryEmbedding, excludeIds, policyConfig.linkExpansionMax, policyConfig);
|
|
256
|
+
if (memories.length === 0) {
|
|
257
|
+
trace.stage('query-expansion', initialResults, {
|
|
258
|
+
entities: expansion.extractedEntities,
|
|
259
|
+
concepts: expansion.extractedConcepts,
|
|
260
|
+
matched: 0,
|
|
261
|
+
expanded: 0,
|
|
262
|
+
});
|
|
263
|
+
return initialResults;
|
|
264
|
+
}
|
|
265
|
+
const merged = mergeStageResults(initialResults, memories, candidateDepth, 1, 1);
|
|
266
|
+
trace.stage('query-expansion', merged, {
|
|
267
|
+
entities: expansion.extractedEntities,
|
|
268
|
+
concepts: expansion.extractedConcepts,
|
|
269
|
+
matched: expansion.matchedEntityIds.length,
|
|
270
|
+
expanded: expansion.expandedMemoryIds.length,
|
|
271
|
+
});
|
|
272
|
+
return merged;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Zero-LLM query augmentation: match the query embedding against entity graph,
|
|
276
|
+
* append matched entity names to the query, and re-embed for better vector targeting.
|
|
277
|
+
* If disabled or no entities match, returns the original query and embedding unchanged.
|
|
278
|
+
*/
|
|
279
|
+
async function applyQueryAugmentation(stores, userId, query, queryEmbedding, trace, policyConfig = config) {
|
|
280
|
+
if (!policyConfig.queryAugmentationEnabled || !policyConfig.entityGraphEnabled || !stores.entity) {
|
|
281
|
+
return { searchQuery: query, augmentedEmbedding: queryEmbedding };
|
|
282
|
+
}
|
|
283
|
+
const result = await augmentQueryWithEntities(stores.entity, userId, query, queryEmbedding, policyConfig);
|
|
284
|
+
if (result.augmentedQuery === query) {
|
|
285
|
+
trace.stage('query-augmentation', [], { matched: 0 });
|
|
286
|
+
return { searchQuery: query, augmentedEmbedding: queryEmbedding };
|
|
287
|
+
}
|
|
288
|
+
const augmentedEmbedding = await embedText(result.augmentedQuery, 'query');
|
|
289
|
+
trace.stage('query-augmentation', [], {
|
|
290
|
+
augmentedQuery: result.augmentedQuery,
|
|
291
|
+
matched: result.matchedEntities.length,
|
|
292
|
+
entities: result.matchedEntities.map((e) => `${e.name} (${e.entityType}, ${e.similarity.toFixed(2)})`),
|
|
293
|
+
});
|
|
294
|
+
return { searchQuery: result.augmentedQuery, augmentedEmbedding };
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Entity name co-retrieval: when the query mentions a known entity by name,
|
|
298
|
+
* pull in ALL memories linked to that entity. This is a zero-LLM exact-match
|
|
299
|
+
* path that ensures fragmented entity facts are reunited at retrieval time.
|
|
300
|
+
*
|
|
301
|
+
* Example: "What plan is Acme Corp on?" → finds "Acme Corp" entity →
|
|
302
|
+
* retrieves pricing, seats, contact, and plan memories together.
|
|
303
|
+
*/
|
|
304
|
+
async function applyEntityNameCoRetrieval(stores, userId, query, queryEmbedding, initialResults, candidateDepth, trace, policyConfig = config) {
|
|
305
|
+
if (!policyConfig.entityGraphEnabled || !stores.entity)
|
|
306
|
+
return initialResults;
|
|
307
|
+
const excludeIds = new Set(initialResults.map((r) => r.id));
|
|
308
|
+
const { memories, matchedNames } = await coRetrieveByEntityNames(stores.entity, stores.search, userId, query, queryEmbedding, excludeIds, policyConfig.linkExpansionMax);
|
|
309
|
+
if (memories.length === 0) {
|
|
310
|
+
trace.stage('entity-coretrieval', initialResults, { candidates: matchedNames, coRetrieved: 0 });
|
|
311
|
+
return initialResults;
|
|
312
|
+
}
|
|
313
|
+
const merged = mergeStageResults(initialResults, memories, candidateDepth, 1, 1);
|
|
314
|
+
trace.stage('entity-coretrieval', merged, {
|
|
315
|
+
matchedNames,
|
|
316
|
+
coRetrieved: memories.length,
|
|
317
|
+
});
|
|
318
|
+
return merged;
|
|
319
|
+
}
|
|
320
|
+
async function applyTemporalQueryExpansion(stores, userId, query, queryEmbedding, initialResults, candidateDepth, referenceTime, trace) {
|
|
321
|
+
const excludeIds = new Set(initialResults.map((result) => result.id));
|
|
322
|
+
const { memories, keywords, anchorIds } = await expandTemporalQuery(stores.search, userId, query, queryEmbedding, excludeIds, candidateDepth, referenceTime);
|
|
323
|
+
const anchorFingerprints = anchorIds
|
|
324
|
+
.map((id) => {
|
|
325
|
+
const anchor = initialResults.find((result) => result.id === id) ?? memories.find((result) => result.id === id);
|
|
326
|
+
return anchor ? buildTemporalFingerprint(anchor.content) : null;
|
|
327
|
+
})
|
|
328
|
+
.filter((fingerprint) => fingerprint !== null);
|
|
329
|
+
if (memories.length === 0) {
|
|
330
|
+
trace.stage('temporal-query-expansion', initialResults, { keywords, expanded: 0 });
|
|
331
|
+
return { memories: initialResults, temporalAnchorFingerprints: anchorFingerprints };
|
|
332
|
+
}
|
|
333
|
+
const mergedPool = mergeStageResults(initialResults, memories, initialResults.length + memories.length, 1, 1);
|
|
334
|
+
const merged = preserveProtectedResults(mergedPool.slice(0, candidateDepth), mergedPool, anchorFingerprints, candidateDepth);
|
|
335
|
+
trace.stage('temporal-query-expansion', merged, {
|
|
336
|
+
keywords,
|
|
337
|
+
anchorIds,
|
|
338
|
+
expanded: memories.length,
|
|
339
|
+
});
|
|
340
|
+
return { memories: merged, temporalAnchorFingerprints: anchorFingerprints };
|
|
341
|
+
}
|
|
342
|
+
async function applyLiteralQueryExpansion(stores, userId, query, queryEmbedding, initialResults, candidateDepth, trace) {
|
|
343
|
+
if (!isLiteralDetailQuery(query)) {
|
|
344
|
+
trace.stage('literal-query-expansion', initialResults, { keywords: [], expanded: 0 });
|
|
345
|
+
return initialResults;
|
|
346
|
+
}
|
|
347
|
+
const excludeIds = new Set(initialResults.map((result) => result.id));
|
|
348
|
+
const { memories, keywords } = await expandLiteralQuery(stores.search, userId, query, queryEmbedding, excludeIds, candidateDepth);
|
|
349
|
+
if (memories.length === 0) {
|
|
350
|
+
trace.stage('literal-query-expansion', initialResults, { keywords, expanded: 0 });
|
|
351
|
+
return initialResults;
|
|
352
|
+
}
|
|
353
|
+
const merged = mergeStageResults(initialResults, memories, initialResults.length + memories.length, 1, 1);
|
|
354
|
+
trace.stage('literal-query-expansion', merged, { keywords, expanded: memories.length });
|
|
355
|
+
return merged;
|
|
356
|
+
}
|
|
357
|
+
async function applySubjectQueryExpansion(stores, userId, query, queryEmbedding, initialResults, candidateDepth, trace) {
|
|
358
|
+
const excludeIds = new Set(initialResults.map((result) => result.id));
|
|
359
|
+
const { memories, anchors } = await expandSubjectQuery(stores.search, userId, query, queryEmbedding, excludeIds, candidateDepth);
|
|
360
|
+
if (memories.length === 0) {
|
|
361
|
+
trace.stage('subject-query-expansion', initialResults, { anchors, expanded: 0 });
|
|
362
|
+
return initialResults;
|
|
363
|
+
}
|
|
364
|
+
const merged = mergeStageResults(initialResults, memories, initialResults.length + memories.length, 1, 1);
|
|
365
|
+
trace.stage('subject-aware-expansion', merged, { anchors, expanded: memories.length });
|
|
366
|
+
return merged;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Apply link expansion (graph or PPR), temporal neighbor expansion, and MMR reranking.
|
|
370
|
+
*/
|
|
371
|
+
async function applyExpansionAndReranking(stores, userId, query, results, queryEmbedding, limit, sourceSite, referenceTime, temporalAnchorFingerprints, trace, skipReranking, policyConfig = config) {
|
|
372
|
+
const reranked = await applyCrossEncoderStage(query, results, skipReranking, trace, policyConfig);
|
|
373
|
+
const ranked = applyRankingProtectionStages(query, reranked, temporalAnchorFingerprints, trace, policyConfig);
|
|
374
|
+
const eligible = applyRankingEligibilityStage(query, ranked, sourceSite, referenceTime, trace, policyConfig);
|
|
375
|
+
return selectAndExpandCandidates(stores, userId, eligible.candidates, queryEmbedding, limit, referenceTime, eligible.protectedFingerprints, trace, policyConfig);
|
|
376
|
+
}
|
|
377
|
+
async function applyCrossEncoderStage(query, results, skipReranking, trace, policyConfig) {
|
|
378
|
+
const shouldSkipRerank = skipReranking || shouldAutoSkipReranking(results, policyConfig);
|
|
379
|
+
if (!policyConfig.crossEncoderEnabled)
|
|
380
|
+
return results;
|
|
381
|
+
if (shouldSkipRerank) {
|
|
382
|
+
console.log(`[reranker] Skipped: ${skipReranking ? 'explicit' : 'auto-skip (high-confidence results)'}`);
|
|
383
|
+
return results;
|
|
384
|
+
}
|
|
385
|
+
const rerankerConfig = {
|
|
386
|
+
crossEncoderModel: policyConfig.crossEncoderModel,
|
|
387
|
+
crossEncoderDtype: policyConfig.crossEncoderDtype,
|
|
388
|
+
};
|
|
389
|
+
const candidates = await rerankCandidates(query, results, rerankerConfig);
|
|
390
|
+
trace.stage('cross-encoder', candidates, {
|
|
391
|
+
model: rerankerConfig.crossEncoderModel,
|
|
392
|
+
dtype: rerankerConfig.crossEncoderDtype,
|
|
393
|
+
});
|
|
394
|
+
return candidates;
|
|
395
|
+
}
|
|
396
|
+
function applyRankingProtectionStages(query, candidates, temporalAnchorFingerprints, trace, policyConfig) {
|
|
397
|
+
let state = applySubjectRankingStage(query, candidates, temporalAnchorFingerprints, trace);
|
|
398
|
+
state = applyLiteralProtectionStage(query, state, trace, policyConfig);
|
|
399
|
+
state = applyTemporalConstraintStage(query, state, trace, policyConfig);
|
|
400
|
+
const currentStateRanked = applyCurrentStateRanking(query, state.candidates);
|
|
401
|
+
if (currentStateRanked.triggered) {
|
|
402
|
+
trace.stage('current-state-ranking', currentStateRanked.results, {});
|
|
403
|
+
state = { ...state, candidates: currentStateRanked.results };
|
|
404
|
+
}
|
|
405
|
+
return { ...state, candidates: applyConcisenessPenalty(state.candidates) };
|
|
406
|
+
}
|
|
407
|
+
function applySubjectRankingStage(query, candidates, protectedFingerprints, trace) {
|
|
408
|
+
const subjectRanked = applySubjectAwareRanking(query, candidates);
|
|
409
|
+
if (subjectRanked.subjects.length === 0)
|
|
410
|
+
return { candidates, protectedFingerprints };
|
|
411
|
+
trace.stage('subject-aware-ranking', subjectRanked.results, {
|
|
412
|
+
subjects: subjectRanked.subjects,
|
|
413
|
+
keywords: subjectRanked.keywords,
|
|
414
|
+
protected: subjectRanked.protectedFingerprints.length,
|
|
415
|
+
});
|
|
416
|
+
return {
|
|
417
|
+
candidates: subjectRanked.results,
|
|
418
|
+
protectedFingerprints: [...protectedFingerprints, ...subjectRanked.protectedFingerprints],
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function applyLiteralProtectionStage(query, state, trace, policyConfig) {
|
|
422
|
+
if (!policyConfig.literalListProtectionEnabled)
|
|
423
|
+
return state;
|
|
424
|
+
const literalProtected = protectLiteralListAnswerCandidates(query, state.candidates, policyConfig.literalListProtectionMaxProtected);
|
|
425
|
+
trace.stage('literal-list-protection', literalProtected.results, {
|
|
426
|
+
protected: literalProtected.protectedFingerprints.length,
|
|
427
|
+
protected_ids: literalProtected.protectedIds,
|
|
428
|
+
reasons: literalProtected.reasons,
|
|
429
|
+
});
|
|
430
|
+
return {
|
|
431
|
+
candidates: literalProtected.results,
|
|
432
|
+
protectedFingerprints: [...state.protectedFingerprints, ...literalProtected.protectedFingerprints],
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function applyTemporalConstraintStage(query, state, trace, policyConfig) {
|
|
436
|
+
if (!policyConfig.temporalQueryConstraintEnabled)
|
|
437
|
+
return state;
|
|
438
|
+
const constrained = applyTemporalQueryConstraints(query, state.candidates, policyConfig.temporalQueryConstraintBoost);
|
|
439
|
+
trace.stage('temporal-query-constraints', constrained.results, {
|
|
440
|
+
constraints: constrained.constraints,
|
|
441
|
+
protected: constrained.protectedFingerprints.length,
|
|
442
|
+
protected_ids: constrained.protectedIds,
|
|
443
|
+
boost: policyConfig.temporalQueryConstraintBoost,
|
|
444
|
+
});
|
|
445
|
+
return {
|
|
446
|
+
candidates: constrained.results,
|
|
447
|
+
protectedFingerprints: [...state.protectedFingerprints, ...constrained.protectedFingerprints],
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function applyRankingEligibilityStage(query, state, sourceSite, referenceTime, trace, policyConfig) {
|
|
451
|
+
const eligibility = applyRankingEligibility(query, state.candidates, policyConfig, {
|
|
452
|
+
sourceSite,
|
|
453
|
+
referenceTime,
|
|
454
|
+
});
|
|
455
|
+
if (!eligibility.triggered)
|
|
456
|
+
return state;
|
|
457
|
+
trace.stage('ranking-eligibility', eligibility.results, {
|
|
458
|
+
threshold: eligibility.threshold,
|
|
459
|
+
reason: eligibility.reason,
|
|
460
|
+
queryLabel: eligibility.queryLabel,
|
|
461
|
+
removedIds: eligibility.removedIds,
|
|
462
|
+
decisions: eligibility.decisions,
|
|
463
|
+
});
|
|
464
|
+
return { ...state, candidates: eligibility.results };
|
|
465
|
+
}
|
|
466
|
+
async function selectAndExpandCandidates(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig) {
|
|
467
|
+
if (policyConfig.linkExpansionBeforeMMR && policyConfig.linkExpansionEnabled && policyConfig.mmrEnabled) {
|
|
468
|
+
return selectWithPreMmrExpansion(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig);
|
|
469
|
+
}
|
|
470
|
+
if (policyConfig.mmrEnabled) {
|
|
471
|
+
return selectWithMmrThenExpand(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig);
|
|
472
|
+
}
|
|
473
|
+
return selectWithoutMmr(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig);
|
|
474
|
+
}
|
|
475
|
+
async function selectWithPreMmrExpansion(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig) {
|
|
476
|
+
const preExpanded = await expandWithLinks(stores, userId, candidates.slice(0, limit), queryEmbedding, referenceTime, policyConfig);
|
|
477
|
+
trace.stage('link-expansion', preExpanded, { order: 'before-mmr' });
|
|
478
|
+
const selected = preserveProtectedResults(applyMMR(preExpanded, queryEmbedding, limit, policyConfig.mmrLambda), preExpanded, protectedFingerprints, limit);
|
|
479
|
+
trace.stage('mmr', selected, { lambda: policyConfig.mmrLambda });
|
|
480
|
+
return selected;
|
|
481
|
+
}
|
|
482
|
+
async function selectWithMmrThenExpand(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig) {
|
|
483
|
+
const mmrResults = preserveProtectedResults(applyMMR(candidates, queryEmbedding, limit, policyConfig.mmrLambda), candidates, protectedFingerprints, limit);
|
|
484
|
+
trace.stage('mmr', mmrResults, { lambda: policyConfig.mmrLambda });
|
|
485
|
+
const expanded = await expandWithLinks(stores, userId, mmrResults, queryEmbedding, referenceTime, policyConfig);
|
|
486
|
+
trace.stage('link-expansion', expanded, { order: 'after-mmr' });
|
|
487
|
+
return expanded;
|
|
488
|
+
}
|
|
489
|
+
async function selectWithoutMmr(stores, userId, candidates, queryEmbedding, limit, referenceTime, protectedFingerprints, trace, policyConfig) {
|
|
490
|
+
const sliced = preserveProtectedResults(candidates.slice(0, limit), candidates, protectedFingerprints, limit);
|
|
491
|
+
const expanded = await expandWithLinks(stores, userId, sliced, queryEmbedding, referenceTime, policyConfig);
|
|
492
|
+
trace.stage('link-expansion', expanded, { order: 'no-mmr' });
|
|
493
|
+
return expanded;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Expand search results with linked memories (graph traversal or PPR)
|
|
497
|
+
* and temporal neighbors.
|
|
498
|
+
*/
|
|
499
|
+
async function expandWithLinks(stores, userId, results, queryEmbedding, referenceTime, policyConfig = config) {
|
|
500
|
+
if (!policyConfig.linkExpansionEnabled || policyConfig.linkExpansionMax <= 0)
|
|
501
|
+
return results;
|
|
502
|
+
const resultIds = results.map((r) => r.id);
|
|
503
|
+
const excludeIds = new Set(resultIds);
|
|
504
|
+
const budget = policyConfig.linkExpansionMax;
|
|
505
|
+
const linkedIds = policyConfig.pprEnabled
|
|
506
|
+
? await expandViaPPR(stores, results, excludeIds, budget, policyConfig)
|
|
507
|
+
: await stores.link.findLinkedMemoryIds(resultIds, excludeIds, budget);
|
|
508
|
+
const temporalNeighbors = await stores.search.findTemporalNeighbors(userId, results.map((r) => r.created_at), queryEmbedding, TEMPORAL_NEIGHBOR_WINDOW_MINUTES, excludeIds, budget, referenceTime);
|
|
509
|
+
const linkedMemories = linkedIds.length > 0
|
|
510
|
+
? await stores.search.fetchMemoriesByIds(userId, linkedIds, queryEmbedding, referenceTime)
|
|
511
|
+
: [];
|
|
512
|
+
const seen = new Set([...resultIds, ...linkedIds]);
|
|
513
|
+
const dedupedTemporal = temporalNeighbors.filter((m) => !seen.has(m.id));
|
|
514
|
+
// Entity graph expansion: find entities matching the query and pull in their linked memories
|
|
515
|
+
const entityMemories = await expandViaEntities(stores, userId, queryEmbedding, seen, budget, policyConfig);
|
|
516
|
+
const expansions = [...linkedMemories, ...dedupedTemporal, ...entityMemories]
|
|
517
|
+
.sort((a, b) => b.score - a.score)
|
|
518
|
+
.slice(0, budget);
|
|
519
|
+
return [...results, ...expansions];
|
|
520
|
+
}
|
|
521
|
+
async function runMemoryRrfRetrieval(stores, userId, queryText, queryEmbedding, limit, sourceSite, referenceTime, includeKeywordChannel, policyConfig = config) {
|
|
522
|
+
const semanticResults = await stores.search.searchSimilar(userId, queryEmbedding, limit, sourceSite, referenceTime);
|
|
523
|
+
const channels = await assembleRrfChannels({
|
|
524
|
+
stores,
|
|
525
|
+
userId,
|
|
526
|
+
queryText,
|
|
527
|
+
queryEmbedding,
|
|
528
|
+
limit,
|
|
529
|
+
sourceSite,
|
|
530
|
+
semanticResults,
|
|
531
|
+
includeKeywordChannel,
|
|
532
|
+
policyConfig,
|
|
533
|
+
});
|
|
534
|
+
const fused = channels.length === 1
|
|
535
|
+
? semanticResults
|
|
536
|
+
: weightedRRF(channels, limit, DEFAULT_RRF_K);
|
|
537
|
+
const reranked = await maybeRerank(queryText, fused, policyConfig);
|
|
538
|
+
return maybeExpandCounterEvidence(stores, userId, reranked, policyConfig);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Counter-evidence expansion (Sprint 3 v1.1, V2 backlog #1). When enabled,
|
|
542
|
+
* looks up belief_edges where any retrieved memory is the target of a
|
|
543
|
+
* COUNTER edge, fetches the counter-source memories, and appends them so
|
|
544
|
+
* the answer LLM sees both halves of recorded contradictions.
|
|
545
|
+
*/
|
|
546
|
+
async function maybeExpandCounterEvidence(stores, userId, candidates, policyConfig) {
|
|
547
|
+
if (!policyConfig.counterEvidenceEnabled)
|
|
548
|
+
return candidates;
|
|
549
|
+
if (candidates.length === 0)
|
|
550
|
+
return candidates;
|
|
551
|
+
try {
|
|
552
|
+
return await expandWithCounterEvidence({ pool: stores.pool }, userId, candidates);
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
console.warn(`[counter-evidence] expansion skipped: ${err.message}`);
|
|
556
|
+
return candidates;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Cross-encoder reranker arm (Sprint 3 v1). Promotes the top-N RRF candidates
|
|
561
|
+
* by LLM-judged relevance. Falls back to the un-reranked list on any failure
|
|
562
|
+
* so a flaky LLM call doesn't break retrieval.
|
|
563
|
+
*/
|
|
564
|
+
async function maybeRerank(queryText, fused, policyConfig) {
|
|
565
|
+
if (!policyConfig.rerankerEnabled || fused.length <= 1)
|
|
566
|
+
return fused;
|
|
567
|
+
const topN = Math.max(2, Math.min(policyConfig.rerankerTopN, fused.length));
|
|
568
|
+
try {
|
|
569
|
+
const head = await llmRerank(queryText, fused.slice(0, topN));
|
|
570
|
+
return [...head, ...fused.slice(topN)];
|
|
571
|
+
}
|
|
572
|
+
catch (err) {
|
|
573
|
+
if (err instanceof RerankerError) {
|
|
574
|
+
console.warn(`[rerank] skipped (${err.message}); falling back to RRF order`);
|
|
575
|
+
return fused;
|
|
576
|
+
}
|
|
577
|
+
throw err;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Build the full set of RRF channels (semantic + entity + keyword + hierarchical
|
|
582
|
+
* + topic + recap). Each is independently gated by config flags. Extracted
|
|
583
|
+
* from runMemoryRrfRetrieval to keep that orchestrator readable as the channel
|
|
584
|
+
* count grows.
|
|
585
|
+
*/
|
|
586
|
+
async function assembleRrfChannels(args) {
|
|
587
|
+
const { stores, userId, queryText, queryEmbedding, limit, sourceSite, semanticResults, includeKeywordChannel, policyConfig } = args;
|
|
588
|
+
const channels = [
|
|
589
|
+
{ name: 'semantic', weight: SEMANTIC_RRF_WEIGHT, results: semanticResults },
|
|
590
|
+
];
|
|
591
|
+
if (policyConfig.entityGraphEnabled && stores.entity) {
|
|
592
|
+
const entityResults = await expandViaEntities(stores, userId, queryEmbedding, new Set(), limit, policyConfig);
|
|
593
|
+
if (entityResults.length > 0) {
|
|
594
|
+
channels.push({ name: 'entity', weight: ENTITY_RRF_WEIGHT, results: entityResults });
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (includeKeywordChannel) {
|
|
598
|
+
const keywordResults = await stores.search.searchKeyword(userId, queryText, limit, sourceSite);
|
|
599
|
+
if (keywordResults.length > 0) {
|
|
600
|
+
channels.push({ name: 'keyword', weight: keywordRrfWeight(), results: keywordResults });
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const hierChannel = await buildHierarchicalChannel(stores, userId, queryEmbedding, semanticResults, policyConfig);
|
|
604
|
+
if (hierChannel)
|
|
605
|
+
channels.push(hierChannel);
|
|
606
|
+
const topicChannel = await buildTopicChannel(stores, userId, queryEmbedding, semanticResults, limit, policyConfig);
|
|
607
|
+
if (topicChannel)
|
|
608
|
+
channels.push(topicChannel);
|
|
609
|
+
const recapChannel = await buildRecapChannel(stores, userId, queryEmbedding, policyConfig);
|
|
610
|
+
if (recapChannel)
|
|
611
|
+
channels.push(recapChannel);
|
|
612
|
+
return channels;
|
|
613
|
+
}
|
|
614
|
+
async function buildTopicChannel(stores, userId, queryEmbedding, semanticResults, limit, policyConfig) {
|
|
615
|
+
if (!policyConfig.topicSearchEnabled)
|
|
616
|
+
return null;
|
|
617
|
+
const topicHits = await stores.search.findTopicCandidates(userId, queryEmbedding, limit * TOPIC_CHANNEL_LIMIT_MULTIPLIER);
|
|
618
|
+
if (topicHits.length === 0)
|
|
619
|
+
return null;
|
|
620
|
+
const topicIds = new Set(topicHits.map((h) => h.id));
|
|
621
|
+
const fused = semanticResults.filter((r) => topicIds.has(r.id));
|
|
622
|
+
if (fused.length === 0)
|
|
623
|
+
return null;
|
|
624
|
+
return { name: 'topic', weight: TOPIC_RRF_WEIGHT, results: fused };
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Recap RRF arm (Sprint 3 v1, cross-session synthesis). Each Recap is a
|
|
628
|
+
* pre-computed narrative aggregating N memories. We surface them as
|
|
629
|
+
* SearchResult-shaped rows (id = recap id, content = recap_text) so the
|
|
630
|
+
* RRF + MMR + answer-prompt assembly downstream don't need to know about
|
|
631
|
+
* a separate "Recap" type. Hits feel like extra-strong abstracted memories.
|
|
632
|
+
*/
|
|
633
|
+
async function buildRecapChannel(stores, userId, queryEmbedding, policyConfig) {
|
|
634
|
+
if (!policyConfig.recapSearchEnabled)
|
|
635
|
+
return null;
|
|
636
|
+
const recapStore = stores.recap;
|
|
637
|
+
if (!recapStore)
|
|
638
|
+
return null;
|
|
639
|
+
const recaps = await recapStore.findRecapCandidates(userId, queryEmbedding, RECAP_CHANNEL_LIMIT);
|
|
640
|
+
if (recaps.length === 0)
|
|
641
|
+
return null;
|
|
642
|
+
const now = new Date();
|
|
643
|
+
const results = recaps.map((r) => ({
|
|
644
|
+
id: r.id,
|
|
645
|
+
user_id: r.user_id,
|
|
646
|
+
content: r.recap_text,
|
|
647
|
+
embedding: r.recap_embedding,
|
|
648
|
+
importance: 1.0,
|
|
649
|
+
similarity: r.similarity,
|
|
650
|
+
source_site: 'recap',
|
|
651
|
+
source_url: '',
|
|
652
|
+
memory_type: 'composite',
|
|
653
|
+
metadata: { recap: true, topic: r.topic, member_count: r.member_count },
|
|
654
|
+
keywords: '',
|
|
655
|
+
summary: '',
|
|
656
|
+
overview: '',
|
|
657
|
+
namespace: null,
|
|
658
|
+
network: 'experience',
|
|
659
|
+
opinion_confidence: null,
|
|
660
|
+
observation_subject: null,
|
|
661
|
+
confidence: 1.0,
|
|
662
|
+
belief_tier: 'standard',
|
|
663
|
+
mutation_type: null,
|
|
664
|
+
observed_at: now,
|
|
665
|
+
created_at: now,
|
|
666
|
+
last_accessed_at: now,
|
|
667
|
+
access_count: 0,
|
|
668
|
+
expired_at: null,
|
|
669
|
+
deleted_at: null,
|
|
670
|
+
episode_id: null,
|
|
671
|
+
workspace_id: null,
|
|
672
|
+
agent_id: null,
|
|
673
|
+
visibility: null,
|
|
674
|
+
status: 'active',
|
|
675
|
+
trust_score: 1.0,
|
|
676
|
+
deferred_audn: false,
|
|
677
|
+
audn_candidates: null,
|
|
678
|
+
}));
|
|
679
|
+
return { name: 'recap', weight: RECAP_RRF_WEIGHT, results };
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* 5th RRF arm: hierarchical (conv→session→atomic). Gated by config flag
|
|
683
|
+
* and presence of a SummariesRepository in the store bundle. Filters arm
|
|
684
|
+
* memory IDs to those that also appear in the semantic top-k so we have
|
|
685
|
+
* full SearchResult payloads to fuse — IDs surfaced ONLY by the
|
|
686
|
+
* hierarchical arm are dropped in v1; full hydration is a follow-up
|
|
687
|
+
* that requires a getMemoriesByIds method on MemoryStore.
|
|
688
|
+
*/
|
|
689
|
+
async function buildHierarchicalChannel(stores, userId, queryEmbedding, semanticResults, policyConfig) {
|
|
690
|
+
if (!policyConfig.hierarchicalRetrievalEnabled || !stores.summaries)
|
|
691
|
+
return null;
|
|
692
|
+
const hierResult = await runHierarchicalArm({ config: policyConfig, summariesRepo: stores.summaries }, userId, queryEmbedding);
|
|
693
|
+
if (hierResult.memoryIds.length === 0)
|
|
694
|
+
return null;
|
|
695
|
+
const semanticById = new Map();
|
|
696
|
+
for (const r of semanticResults)
|
|
697
|
+
semanticById.set(r.id, r);
|
|
698
|
+
const ordered = [];
|
|
699
|
+
for (const id of hierResult.memoryIds) {
|
|
700
|
+
const hit = semanticById.get(id);
|
|
701
|
+
if (hit)
|
|
702
|
+
ordered.push(hit);
|
|
703
|
+
}
|
|
704
|
+
if (ordered.length === 0)
|
|
705
|
+
return null;
|
|
706
|
+
return { name: 'hierarchical', weight: HIERARCHICAL_RRF_WEIGHT, results: ordered };
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Use Personalized PageRank to find expansion candidates from the link graph.
|
|
710
|
+
*/
|
|
711
|
+
async function expandViaPPR(stores, results, excludeIds, budget, policyConfig = config) {
|
|
712
|
+
const seedScores = new Map();
|
|
713
|
+
for (const r of results) {
|
|
714
|
+
seedScores.set(r.id, r.score);
|
|
715
|
+
}
|
|
716
|
+
const { scores } = await personalizedPageRank(stores.pool, seedScores, { damping: policyConfig.pprDamping });
|
|
717
|
+
return [...scores.entries()]
|
|
718
|
+
.filter(([id]) => !excludeIds.has(id))
|
|
719
|
+
.sort(([, a], [, b]) => b - a)
|
|
720
|
+
.slice(0, budget)
|
|
721
|
+
.map(([id]) => id);
|
|
722
|
+
}
|
|
723
|
+
function mergeStageResults(primary, secondary, limit, primaryWeight, secondaryWeight) {
|
|
724
|
+
const merged = new Map();
|
|
725
|
+
mergeStageWeightedResults(merged, primary, primaryWeight);
|
|
726
|
+
mergeStageWeightedResults(merged, secondary, secondaryWeight);
|
|
727
|
+
return [...merged.values()]
|
|
728
|
+
.sort((left, right) => right.score - left.score)
|
|
729
|
+
.slice(0, limit);
|
|
730
|
+
}
|
|
731
|
+
function mergeStageWeightedResults(merged, results, weight) {
|
|
732
|
+
for (const result of results) {
|
|
733
|
+
const weighted = { ...result, score: result.score * weight };
|
|
734
|
+
const existing = merged.get(result.id);
|
|
735
|
+
if (!existing || weighted.score > existing.score) {
|
|
736
|
+
merged.set(result.id, weighted);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Generate similarity links between newly ingested memories and existing ones.
|
|
742
|
+
* Only runs when link expansion is enabled.
|
|
743
|
+
*/
|
|
744
|
+
export async function generateLinks(stores, userId, memoryIds, embeddingCache, runtimeConfig = config) {
|
|
745
|
+
if (!runtimeConfig.linkExpansionEnabled || memoryIds.length === 0)
|
|
746
|
+
return 0;
|
|
747
|
+
const activeMemoryIds = [];
|
|
748
|
+
for (const id of memoryIds) {
|
|
749
|
+
const memory = await stores.memory.getMemory(id, userId);
|
|
750
|
+
if (memory)
|
|
751
|
+
activeMemoryIds.push(id);
|
|
752
|
+
}
|
|
753
|
+
if (activeMemoryIds.length === 0)
|
|
754
|
+
return 0;
|
|
755
|
+
const allLinks = [];
|
|
756
|
+
for (const memoryId of activeMemoryIds) {
|
|
757
|
+
const embedding = embeddingCache.get(memoryId);
|
|
758
|
+
if (!embedding)
|
|
759
|
+
continue;
|
|
760
|
+
const candidates = await stores.link.findLinkCandidates(userId, embedding, runtimeConfig.linkSimilarityThreshold, memoryId);
|
|
761
|
+
for (const candidate of candidates) {
|
|
762
|
+
allLinks.push({ sourceId: memoryId, targetId: candidate.id, similarity: candidate.similarity });
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
if (allLinks.length === 0)
|
|
766
|
+
return 0;
|
|
767
|
+
return stores.link.createLinks(allLinks);
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Entity graph expansion: find entities matching the query embedding,
|
|
771
|
+
* traverse relations to find connected entities (1-hop), then retrieve
|
|
772
|
+
* memories linked to all matched entities.
|
|
773
|
+
*/
|
|
774
|
+
async function expandViaEntities(stores, userId, queryEmbedding, excludeIds, budget, policyConfig = config) {
|
|
775
|
+
if (!policyConfig.entityGraphEnabled || !stores.entity)
|
|
776
|
+
return [];
|
|
777
|
+
const matchingEntities = await stores.entity.searchEntities(userId, queryEmbedding, 5, policyConfig.entitySearchMinSimilarity);
|
|
778
|
+
if (matchingEntities.length === 0)
|
|
779
|
+
return [];
|
|
780
|
+
const directEntityIds = matchingEntities.map((e) => e.id);
|
|
781
|
+
// 1-hop relation traversal: find entities connected via relations
|
|
782
|
+
const relatedEntityIds = await stores.entity.findRelatedEntityIds(userId, directEntityIds, new Set(directEntityIds), budget);
|
|
783
|
+
const allEntityIds = [...directEntityIds, ...relatedEntityIds];
|
|
784
|
+
const memoryIds = await stores.entity.findMemoryIdsByEntities(userId, allEntityIds, excludeIds, budget);
|
|
785
|
+
if (memoryIds.length === 0)
|
|
786
|
+
return [];
|
|
787
|
+
return stores.search.fetchMemoriesByIds(userId, memoryIds, queryEmbedding);
|
|
788
|
+
}
|