@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,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chunked extraction — splits conversations into overlapping turn windows
|
|
3
|
+
* before extracting facts. Helps smaller LLMs (e.g. qwen3:8b) that struggle
|
|
4
|
+
* with long contexts by giving them focused 3-4 turn windows instead of the
|
|
5
|
+
* full conversation.
|
|
6
|
+
*
|
|
7
|
+
* Each chunk includes a session date header and overlap with the previous
|
|
8
|
+
* chunk to preserve cross-turn context. Facts are deduplicated across chunks
|
|
9
|
+
* using embedding similarity.
|
|
10
|
+
*/
|
|
11
|
+
import { extractFacts } from './extraction.js';
|
|
12
|
+
import { cachedExtractFacts } from './extraction-cache.js';
|
|
13
|
+
import { cosineSimilarity, embedText } from './embedding.js';
|
|
14
|
+
const DEDUP_SIMILARITY_THRESHOLD = 0.92;
|
|
15
|
+
/**
|
|
16
|
+
* Split conversation text into overlapping turn-based chunks.
|
|
17
|
+
* Expects format: "[Session date: YYYY-MM-DD]\nSpeaker: text\nSpeaker: text\n..."
|
|
18
|
+
*/
|
|
19
|
+
function chunkConversation(conversationText, chunkSize, overlap) {
|
|
20
|
+
const lines = conversationText.split('\n');
|
|
21
|
+
// Extract session header (first line if it starts with "[Session")
|
|
22
|
+
let header = '';
|
|
23
|
+
let turnLines = [];
|
|
24
|
+
if (lines[0]?.startsWith('[Session')) {
|
|
25
|
+
header = lines[0];
|
|
26
|
+
turnLines = lines.slice(1).filter((l) => l.trim().length > 0);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
turnLines = lines.filter((l) => l.trim().length > 0);
|
|
30
|
+
}
|
|
31
|
+
// Each turn is a line matching "Speaker: text"
|
|
32
|
+
const turns = turnLines.filter((l) => /^\w[\w\s]*:/.test(l));
|
|
33
|
+
if (turns.length <= chunkSize) {
|
|
34
|
+
return [conversationText];
|
|
35
|
+
}
|
|
36
|
+
const chunks = [];
|
|
37
|
+
const step = Math.max(1, chunkSize - overlap);
|
|
38
|
+
for (let i = 0; i < turns.length; i += step) {
|
|
39
|
+
const chunkTurns = turns.slice(i, i + chunkSize);
|
|
40
|
+
if (chunkTurns.length === 0)
|
|
41
|
+
break;
|
|
42
|
+
const chunkText = header
|
|
43
|
+
? `${header}\n${chunkTurns.join('\n')}`
|
|
44
|
+
: chunkTurns.join('\n');
|
|
45
|
+
chunks.push(chunkText);
|
|
46
|
+
if (i + chunkSize >= turns.length)
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
return chunks;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extract facts from each chunk and deduplicate across chunks.
|
|
53
|
+
* Uses embedding similarity to detect duplicate facts from overlapping windows.
|
|
54
|
+
*/
|
|
55
|
+
export async function chunkedExtractFacts(conversationText, options = {}, chunking) {
|
|
56
|
+
const chunks = chunkConversation(conversationText, chunking.chunkSizeTurns, chunking.chunkOverlapTurns);
|
|
57
|
+
if (chunks.length <= 1) {
|
|
58
|
+
return chunking.extractionCacheEnabled
|
|
59
|
+
? cachedExtractFacts(conversationText, options)
|
|
60
|
+
: extractFacts(conversationText, options);
|
|
61
|
+
}
|
|
62
|
+
// Extract facts from each chunk
|
|
63
|
+
const allFacts = [];
|
|
64
|
+
for (const chunk of chunks) {
|
|
65
|
+
const facts = chunking.extractionCacheEnabled
|
|
66
|
+
? await cachedExtractFacts(chunk, options)
|
|
67
|
+
: await extractFacts(chunk, options);
|
|
68
|
+
allFacts.push(...facts);
|
|
69
|
+
}
|
|
70
|
+
if (allFacts.length === 0)
|
|
71
|
+
return [];
|
|
72
|
+
// Deduplicate using embedding similarity
|
|
73
|
+
return deduplicateFacts(allFacts);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Remove near-duplicate facts by comparing embeddings.
|
|
77
|
+
* Keeps the first occurrence (from earlier chunks) when duplicates found.
|
|
78
|
+
*/
|
|
79
|
+
async function deduplicateFacts(facts) {
|
|
80
|
+
if (facts.length <= 1)
|
|
81
|
+
return facts;
|
|
82
|
+
const embeddings = await Promise.all(facts.map((f) => embedText(f.fact)));
|
|
83
|
+
const kept = markDuplicates(facts, embeddings);
|
|
84
|
+
return facts.filter((_, i) => kept[i]);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Pairwise comparison to mark near-duplicate facts.
|
|
88
|
+
* Keeps the higher-importance fact when duplicates are found.
|
|
89
|
+
*/
|
|
90
|
+
function markDuplicates(facts, embeddings) {
|
|
91
|
+
const kept = new Array(facts.length).fill(true);
|
|
92
|
+
for (let i = 0; i < facts.length; i++) {
|
|
93
|
+
if (!kept[i])
|
|
94
|
+
continue;
|
|
95
|
+
for (let j = i + 1; j < facts.length; j++) {
|
|
96
|
+
if (!kept[j])
|
|
97
|
+
continue;
|
|
98
|
+
if (cosineSimilarity(embeddings[i], embeddings[j]) < DEDUP_SIMILARITY_THRESHOLD)
|
|
99
|
+
continue;
|
|
100
|
+
if (facts[j].importance > facts[i].importance) {
|
|
101
|
+
kept[i] = false;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
kept[j] = false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return kept;
|
|
108
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic claim slot helpers.
|
|
3
|
+
* Slots only form for relation-backed facts whose entities already resolve to
|
|
4
|
+
* canonical IDs. This gives the temporal layer a stable overwrite target
|
|
5
|
+
* without guessing semantics for every free-form sentence.
|
|
6
|
+
*/
|
|
7
|
+
import { type RelationType, type EntityType } from '../db/repository-types.js';
|
|
8
|
+
import { type ExtractedRelation } from './extraction.js';
|
|
9
|
+
export interface CanonicalEntityRef {
|
|
10
|
+
extractedName: string;
|
|
11
|
+
entityId: string;
|
|
12
|
+
canonicalName: string;
|
|
13
|
+
entityType: EntityType;
|
|
14
|
+
}
|
|
15
|
+
export interface ClaimSlotDescriptor {
|
|
16
|
+
slotKey: string;
|
|
17
|
+
subjectEntityId: string;
|
|
18
|
+
relationType: RelationType;
|
|
19
|
+
objectEntityId: string;
|
|
20
|
+
}
|
|
21
|
+
export interface PersistedRelationSlot {
|
|
22
|
+
sourceEntityId: string;
|
|
23
|
+
targetEntityId: string;
|
|
24
|
+
relationType: RelationType;
|
|
25
|
+
}
|
|
26
|
+
export declare function buildRelationClaimSlot(relations: ExtractedRelation[], canonicalEntities: Map<string, CanonicalEntityRef>): ClaimSlotDescriptor | null;
|
|
27
|
+
export declare function buildPersistedRelationClaimSlot(relations: PersistedRelationSlot[]): ClaimSlotDescriptor | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic claim slot helpers.
|
|
3
|
+
* Slots only form for relation-backed facts whose entities already resolve to
|
|
4
|
+
* canonical IDs. This gives the temporal layer a stable overwrite target
|
|
5
|
+
* without guessing semantics for every free-form sentence.
|
|
6
|
+
*/
|
|
7
|
+
export function buildRelationClaimSlot(relations, canonicalEntities) {
|
|
8
|
+
const candidates = relations
|
|
9
|
+
.map((relation) => buildRelationSlotCandidate(relation, canonicalEntities))
|
|
10
|
+
.filter((candidate) => candidate !== null)
|
|
11
|
+
.sort((left, right) => left.slotKey.localeCompare(right.slotKey));
|
|
12
|
+
return candidates[0] ?? null;
|
|
13
|
+
}
|
|
14
|
+
export function buildPersistedRelationClaimSlot(relations) {
|
|
15
|
+
const candidates = relations
|
|
16
|
+
.filter((relation) => relation.sourceEntityId !== relation.targetEntityId)
|
|
17
|
+
.map((relation) => ({
|
|
18
|
+
slotKey: `relation:${relation.sourceEntityId}:${relation.relationType}:${relation.targetEntityId}`,
|
|
19
|
+
subjectEntityId: relation.sourceEntityId,
|
|
20
|
+
relationType: relation.relationType,
|
|
21
|
+
objectEntityId: relation.targetEntityId,
|
|
22
|
+
}))
|
|
23
|
+
.sort((left, right) => left.slotKey.localeCompare(right.slotKey));
|
|
24
|
+
return candidates[0] ?? null;
|
|
25
|
+
}
|
|
26
|
+
function buildRelationSlotCandidate(relation, canonicalEntities) {
|
|
27
|
+
const source = canonicalEntities.get(relation.source.toLowerCase());
|
|
28
|
+
const target = canonicalEntities.get(relation.target.toLowerCase());
|
|
29
|
+
if (!source || !target || source.entityId === target.entityId) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
slotKey: `relation:${source.entityId}:${relation.type}:${target.entityId}`,
|
|
34
|
+
subjectEntityId: source.entityId,
|
|
35
|
+
relationType: relation.type,
|
|
36
|
+
objectEntityId: target.entityId,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Agent SDK-backed LLM provider.
|
|
3
|
+
*
|
|
4
|
+
* This provider is intended for local developer setups where the `claude`
|
|
5
|
+
* CLI is already authenticated. It disables tools, MCP servers, settings,
|
|
6
|
+
* project context, and session persistence so extraction stays close to a
|
|
7
|
+
* one-turn chat completion instead of becoming an agent run.
|
|
8
|
+
*/
|
|
9
|
+
import type { ChatMessage, ChatOptions, LLMProvider } from './llm.js';
|
|
10
|
+
import { type WriteCostEventConfig } from './cost-telemetry.js';
|
|
11
|
+
export interface ClaudeCodeLLMConfig extends WriteCostEventConfig {
|
|
12
|
+
llmProvider: 'claude-code';
|
|
13
|
+
llmModel: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class ClaudeCodeLLM implements LLMProvider {
|
|
16
|
+
private readonly config;
|
|
17
|
+
constructor(config: ClaudeCodeLLMConfig);
|
|
18
|
+
chat(messages: ChatMessage[], options?: ChatOptions): Promise<string>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Agent SDK-backed LLM provider.
|
|
3
|
+
*
|
|
4
|
+
* This provider is intended for local developer setups where the `claude`
|
|
5
|
+
* CLI is already authenticated. It disables tools, MCP servers, settings,
|
|
6
|
+
* project context, and session persistence so extraction stays close to a
|
|
7
|
+
* one-turn chat completion instead of becoming an agent run.
|
|
8
|
+
*/
|
|
9
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
10
|
+
import { estimateCostUsd, getCostStage, summarizeUsage, writeCostEvent, } from './cost-telemetry.js';
|
|
11
|
+
export class ClaudeCodeLLM {
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
async chat(messages, options = {}) {
|
|
17
|
+
const started = performance.now();
|
|
18
|
+
const result = await runClaudeCodeQuery(buildPrompt(messages), buildClaudeCodeOptions(messages, this.config.llmModel, options));
|
|
19
|
+
if (result.subtype !== 'success') {
|
|
20
|
+
throw new Error(`Claude Code LLM failed: ${result.errors.join('; ')}`);
|
|
21
|
+
}
|
|
22
|
+
recordClaudeCodeCost(this.config, result, started);
|
|
23
|
+
return result.result.trim();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function buildPrompt(messages) {
|
|
27
|
+
return messages
|
|
28
|
+
.filter((message) => message.role !== 'system')
|
|
29
|
+
.map((message) => `${message.role.toUpperCase()}:\n${message.content}`)
|
|
30
|
+
.join('\n\n')
|
|
31
|
+
.trim();
|
|
32
|
+
}
|
|
33
|
+
function buildClaudeCodeOptions(messages, model, options) {
|
|
34
|
+
const systemPrompt = buildSystemPrompt(messages, options);
|
|
35
|
+
return {
|
|
36
|
+
...(model ? { model } : {}),
|
|
37
|
+
...(systemPrompt ? { systemPrompt } : {}),
|
|
38
|
+
tools: [],
|
|
39
|
+
mcpServers: {},
|
|
40
|
+
settingSources: [],
|
|
41
|
+
persistSession: false,
|
|
42
|
+
permissionMode: 'dontAsk',
|
|
43
|
+
maxTurns: 1,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function buildSystemPrompt(messages, options) {
|
|
47
|
+
const system = messages
|
|
48
|
+
.filter((message) => message.role === 'system')
|
|
49
|
+
.map((message) => message.content)
|
|
50
|
+
.join('\n\n')
|
|
51
|
+
.trim();
|
|
52
|
+
if (!options.jsonMode)
|
|
53
|
+
return system;
|
|
54
|
+
return [system, 'Return only valid JSON. Do not include markdown fences or commentary.']
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.join('\n\n');
|
|
57
|
+
}
|
|
58
|
+
async function runClaudeCodeQuery(prompt, options) {
|
|
59
|
+
let result = null;
|
|
60
|
+
try {
|
|
61
|
+
for await (const message of query({ prompt, options })) {
|
|
62
|
+
if (message.type === 'result')
|
|
63
|
+
result = message;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw new Error('Claude Code LLM failed to run. Confirm `claude` is installed and authenticated: ' +
|
|
68
|
+
errorMessage(error));
|
|
69
|
+
}
|
|
70
|
+
if (!result)
|
|
71
|
+
throw new Error('Claude Code LLM ended without a result message');
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function recordClaudeCodeCost(config, result, started) {
|
|
75
|
+
const usage = summarizeUsage(sumModelUsage(result.modelUsage, 'inputTokens'), sumModelUsage(result.modelUsage, 'outputTokens'), null);
|
|
76
|
+
const model = config.llmModel || Object.keys(result.modelUsage)[0] || 'claude-code';
|
|
77
|
+
writeCostEvent({
|
|
78
|
+
stage: getCostStage(),
|
|
79
|
+
provider: config.llmProvider,
|
|
80
|
+
model,
|
|
81
|
+
requestKind: 'chat',
|
|
82
|
+
durationMs: performance.now() - started,
|
|
83
|
+
cacheHit: false,
|
|
84
|
+
inputTokens: usage.inputTokens ?? null,
|
|
85
|
+
outputTokens: usage.outputTokens ?? null,
|
|
86
|
+
totalTokens: usage.totalTokens ?? null,
|
|
87
|
+
estimatedCostUsd: result.total_cost_usd ?? estimateCostUsd(config.llmProvider, model, usage),
|
|
88
|
+
}, config);
|
|
89
|
+
}
|
|
90
|
+
function sumModelUsage(usage, field) {
|
|
91
|
+
const total = Object.values(usage).reduce((sum, item) => sum + (item[field] ?? 0), 0);
|
|
92
|
+
return total > 0 ? total : null;
|
|
93
|
+
}
|
|
94
|
+
function errorMessage(error) {
|
|
95
|
+
return error instanceof Error ? error.message : String(error);
|
|
96
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite/member deduplication for injection packaging.
|
|
3
|
+
*
|
|
4
|
+
* Two strategies:
|
|
5
|
+
*
|
|
6
|
+
* 1. `deduplicateCompositeMembersHard` — tiered mode: if a composite and its
|
|
7
|
+
* member atomics both appear, keep the composite and drop covered atomics.
|
|
8
|
+
*
|
|
9
|
+
* 2. `deduplicateCompositeMembersSoft` — flat/default mode: use a coverage-
|
|
10
|
+
* ratio threshold. If the selected atomics already cover ≥60% of a
|
|
11
|
+
* composite's members, suppress the composite (the atomics are more
|
|
12
|
+
* precise). Otherwise keep both.
|
|
13
|
+
*
|
|
14
|
+
* See: design/composite-vs-atomic-retrieval-contract-2026-03-27.md §Dedup rule
|
|
15
|
+
*/
|
|
16
|
+
import type { SearchResult } from '../db/repository-types.js';
|
|
17
|
+
import type { RetrievalMode } from './memory-service-types.js';
|
|
18
|
+
import type { TraceCollector } from './retrieval-trace.js';
|
|
19
|
+
/**
|
|
20
|
+
* Hard dedup for tiered mode: composites win, covered atomics are dropped.
|
|
21
|
+
* This is the existing behavior extracted from memory-service.ts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function deduplicateCompositeMembersHard(memories: SearchResult[]): SearchResult[];
|
|
24
|
+
/**
|
|
25
|
+
* Soft dedup for flat/default mode: suppress composites when selected atomics
|
|
26
|
+
* already cover a high fraction of the composite's members.
|
|
27
|
+
*
|
|
28
|
+
* Logic:
|
|
29
|
+
* coverage = |composite.memberIds ∩ selectedAtomicIds| / |composite.memberIds|
|
|
30
|
+
* if coverage ≥ threshold → suppress the composite (atomics are enough)
|
|
31
|
+
* if coverage < threshold → keep the composite (it adds uncovered content)
|
|
32
|
+
*
|
|
33
|
+
* Atomics are never suppressed — they are the precision layer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function deduplicateCompositeMembersSoft(memories: SearchResult[], coverageThreshold?: number): SearchResult[];
|
|
36
|
+
/**
|
|
37
|
+
* Flat-mode packaging policy for precision queries. If the query asks for a
|
|
38
|
+
* specific current or direct factual answer, any composite that overlaps with
|
|
39
|
+
* already-retrieved atomics is treated as redundant and removed.
|
|
40
|
+
*
|
|
41
|
+
* Broad queries still use the softer coverage-ratio threshold because
|
|
42
|
+
* compression is usually beneficial there.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deduplicateCompositeMembersForFlatQuery(memories: SearchResult[], query: string, coverageThreshold?: number): SearchResult[];
|
|
45
|
+
export declare function prefersAtomicFlatPackaging(query: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Apply flat-mode composite dedup and record the dedup as a trace stage
|
|
48
|
+
* if the result set changed. No-op for non-flat modes or empty sets.
|
|
49
|
+
*/
|
|
50
|
+
export declare function applyFlatPackagingPolicy(memories: SearchResult[], query: string, mode: RetrievalMode, trace: TraceCollector): SearchResult[];
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite/member deduplication for injection packaging.
|
|
3
|
+
*
|
|
4
|
+
* Two strategies:
|
|
5
|
+
*
|
|
6
|
+
* 1. `deduplicateCompositeMembersHard` — tiered mode: if a composite and its
|
|
7
|
+
* member atomics both appear, keep the composite and drop covered atomics.
|
|
8
|
+
*
|
|
9
|
+
* 2. `deduplicateCompositeMembersSoft` — flat/default mode: use a coverage-
|
|
10
|
+
* ratio threshold. If the selected atomics already cover ≥60% of a
|
|
11
|
+
* composite's members, suppress the composite (the atomics are more
|
|
12
|
+
* precise). Otherwise keep both.
|
|
13
|
+
*
|
|
14
|
+
* See: design/composite-vs-atomic-retrieval-contract-2026-03-27.md §Dedup rule
|
|
15
|
+
*/
|
|
16
|
+
import { isCurrentStateQuery } from './current-state-ranking.js';
|
|
17
|
+
const DEFAULT_COVERAGE_THRESHOLD = 0.6;
|
|
18
|
+
const BROAD_QUERY_MARKERS = [
|
|
19
|
+
'summarize',
|
|
20
|
+
'summary',
|
|
21
|
+
'overview',
|
|
22
|
+
'what should the assistant know',
|
|
23
|
+
'tell me about',
|
|
24
|
+
'recap',
|
|
25
|
+
'background',
|
|
26
|
+
'context',
|
|
27
|
+
];
|
|
28
|
+
const DIRECT_QUERY_STARTERS = ['who ', 'what ', 'which ', 'where '];
|
|
29
|
+
const MAX_DIRECT_QUERY_WORDS = 10;
|
|
30
|
+
/**
|
|
31
|
+
* Hard dedup for tiered mode: composites win, covered atomics are dropped.
|
|
32
|
+
* This is the existing behavior extracted from memory-service.ts.
|
|
33
|
+
*/
|
|
34
|
+
export function deduplicateCompositeMembersHard(memories) {
|
|
35
|
+
const composites = memories.filter((m) => m.memory_type === 'composite');
|
|
36
|
+
if (composites.length === 0)
|
|
37
|
+
return memories;
|
|
38
|
+
const coveredIds = new Set();
|
|
39
|
+
for (const composite of composites) {
|
|
40
|
+
const memberIds = composite.metadata?.memberMemoryIds;
|
|
41
|
+
if (Array.isArray(memberIds)) {
|
|
42
|
+
for (const id of memberIds) {
|
|
43
|
+
if (typeof id === 'string')
|
|
44
|
+
coveredIds.add(id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (coveredIds.size === 0)
|
|
49
|
+
return memories;
|
|
50
|
+
return memories.filter((m) => m.memory_type === 'composite' || !coveredIds.has(m.id));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Soft dedup for flat/default mode: suppress composites when selected atomics
|
|
54
|
+
* already cover a high fraction of the composite's members.
|
|
55
|
+
*
|
|
56
|
+
* Logic:
|
|
57
|
+
* coverage = |composite.memberIds ∩ selectedAtomicIds| / |composite.memberIds|
|
|
58
|
+
* if coverage ≥ threshold → suppress the composite (atomics are enough)
|
|
59
|
+
* if coverage < threshold → keep the composite (it adds uncovered content)
|
|
60
|
+
*
|
|
61
|
+
* Atomics are never suppressed — they are the precision layer.
|
|
62
|
+
*/
|
|
63
|
+
export function deduplicateCompositeMembersSoft(memories, coverageThreshold = DEFAULT_COVERAGE_THRESHOLD) {
|
|
64
|
+
const composites = memories.filter((m) => m.memory_type === 'composite');
|
|
65
|
+
if (composites.length === 0)
|
|
66
|
+
return memories;
|
|
67
|
+
const atomicIds = new Set(memories
|
|
68
|
+
.filter((m) => m.memory_type !== 'composite')
|
|
69
|
+
.map((m) => m.id));
|
|
70
|
+
if (atomicIds.size === 0)
|
|
71
|
+
return memories;
|
|
72
|
+
const suppressedCompositeIds = new Set();
|
|
73
|
+
for (const composite of composites) {
|
|
74
|
+
const memberIds = composite.metadata?.memberMemoryIds;
|
|
75
|
+
if (!Array.isArray(memberIds) || memberIds.length === 0)
|
|
76
|
+
continue;
|
|
77
|
+
const validMemberIds = memberIds.filter((id) => typeof id === 'string');
|
|
78
|
+
if (validMemberIds.length === 0)
|
|
79
|
+
continue;
|
|
80
|
+
const coveredCount = validMemberIds.filter((id) => atomicIds.has(id)).length;
|
|
81
|
+
const coverageRatio = coveredCount / validMemberIds.length;
|
|
82
|
+
if (coverageRatio >= coverageThreshold) {
|
|
83
|
+
suppressedCompositeIds.add(composite.id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (suppressedCompositeIds.size === 0)
|
|
87
|
+
return memories;
|
|
88
|
+
return memories.filter((m) => !suppressedCompositeIds.has(m.id));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Flat-mode packaging policy for precision queries. If the query asks for a
|
|
92
|
+
* specific current or direct factual answer, any composite that overlaps with
|
|
93
|
+
* already-retrieved atomics is treated as redundant and removed.
|
|
94
|
+
*
|
|
95
|
+
* Broad queries still use the softer coverage-ratio threshold because
|
|
96
|
+
* compression is usually beneficial there.
|
|
97
|
+
*/
|
|
98
|
+
export function deduplicateCompositeMembersForFlatQuery(memories, query, coverageThreshold = DEFAULT_COVERAGE_THRESHOLD) {
|
|
99
|
+
if (!prefersAtomicFlatPackaging(query)) {
|
|
100
|
+
return deduplicateCompositeMembersSoft(memories, coverageThreshold);
|
|
101
|
+
}
|
|
102
|
+
return suppressOverlappingComposites(memories);
|
|
103
|
+
}
|
|
104
|
+
export function prefersAtomicFlatPackaging(query) {
|
|
105
|
+
const normalized = normalizeQuery(query);
|
|
106
|
+
if (BROAD_QUERY_MARKERS.some((marker) => normalized.includes(marker)))
|
|
107
|
+
return false;
|
|
108
|
+
if (isCurrentStateQuery(query))
|
|
109
|
+
return true;
|
|
110
|
+
return DIRECT_QUERY_STARTERS.some((starter) => normalized.startsWith(starter))
|
|
111
|
+
&& normalized.split(/\s+/).length <= MAX_DIRECT_QUERY_WORDS;
|
|
112
|
+
}
|
|
113
|
+
function suppressOverlappingComposites(memories) {
|
|
114
|
+
const atomicIds = new Set(memories
|
|
115
|
+
.filter((memory) => memory.memory_type !== 'composite')
|
|
116
|
+
.map((memory) => memory.id));
|
|
117
|
+
if (atomicIds.size === 0)
|
|
118
|
+
return memories;
|
|
119
|
+
const overlappingCompositeIds = new Set(memories
|
|
120
|
+
.filter((memory) => memory.memory_type === 'composite')
|
|
121
|
+
.filter((memory) => parseMemberIds(memory).some((id) => atomicIds.has(id)))
|
|
122
|
+
.map((memory) => memory.id));
|
|
123
|
+
if (overlappingCompositeIds.size === 0)
|
|
124
|
+
return memories;
|
|
125
|
+
return memories.filter((memory) => !overlappingCompositeIds.has(memory.id));
|
|
126
|
+
}
|
|
127
|
+
function normalizeQuery(query) {
|
|
128
|
+
return query.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
129
|
+
}
|
|
130
|
+
function parseMemberIds(memory) {
|
|
131
|
+
const candidate = memory.metadata?.memberMemoryIds;
|
|
132
|
+
if (!Array.isArray(candidate))
|
|
133
|
+
return [];
|
|
134
|
+
return candidate.filter((id) => typeof id === 'string');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Apply flat-mode composite dedup and record the dedup as a trace stage
|
|
138
|
+
* if the result set changed. No-op for non-flat modes or empty sets.
|
|
139
|
+
*/
|
|
140
|
+
export function applyFlatPackagingPolicy(memories, query, mode, trace) {
|
|
141
|
+
if (mode !== 'flat' || memories.length === 0)
|
|
142
|
+
return memories;
|
|
143
|
+
const packaged = deduplicateCompositeMembersForFlatQuery(memories, query);
|
|
144
|
+
if (packaged.length === memories.length && packaged[0]?.id === memories[0]?.id) {
|
|
145
|
+
return memories;
|
|
146
|
+
}
|
|
147
|
+
trace.stage('flat-packaging-dedup', packaged, {
|
|
148
|
+
removedIds: memories
|
|
149
|
+
.map((memory) => memory.id)
|
|
150
|
+
.filter((id) => !packaged.some((memory) => memory.id === id)),
|
|
151
|
+
});
|
|
152
|
+
return packaged;
|
|
153
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite Memory Grouping — clusters related atomic facts from a single episode
|
|
3
|
+
* into paragraph-length composite memories that benefit from tiered loading (L0/L1/L2).
|
|
4
|
+
*
|
|
5
|
+
* Atomistic extraction produces single-sentence facts (median ~80 chars) where
|
|
6
|
+
* L1 overviews are identical to L2 content, making tiered retrieval degenerate to
|
|
7
|
+
* flat mode. Composites bridge this gap: they join related facts into paragraph-length
|
|
8
|
+
* content that generateL1Overview() can meaningfully compress.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm: Greedy single-linkage clustering on cosine similarity of fact embeddings.
|
|
11
|
+
* Clusters with < minClusterSize members are skipped (no compression benefit).
|
|
12
|
+
*/
|
|
13
|
+
export interface CompositeInput {
|
|
14
|
+
memoryId: string;
|
|
15
|
+
content: string;
|
|
16
|
+
embedding: number[];
|
|
17
|
+
importance: number;
|
|
18
|
+
keywords: string[];
|
|
19
|
+
headline: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CompositeMemory {
|
|
22
|
+
/** Paragraph joining member facts in importance-descending order. */
|
|
23
|
+
content: string;
|
|
24
|
+
/** L0: headline from the most important member fact. */
|
|
25
|
+
headline: string;
|
|
26
|
+
/** L1: overview generated from the composite content (first 2-3 sentences). */
|
|
27
|
+
overview: string;
|
|
28
|
+
/** Centroid of member fact embeddings. */
|
|
29
|
+
embedding: number[];
|
|
30
|
+
/** Max importance across member facts. */
|
|
31
|
+
importance: number;
|
|
32
|
+
/** Union of all member keywords, deduplicated. */
|
|
33
|
+
keywords: string[];
|
|
34
|
+
/** IDs of the atomic memories grouped into this composite. */
|
|
35
|
+
memberMemoryIds: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Group facts from a single episode into composite memories by topic similarity.
|
|
39
|
+
* Returns only composites with ≥ minClusterSize members.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildComposites(facts: CompositeInput[]): CompositeMemory[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite Memory Grouping — clusters related atomic facts from a single episode
|
|
3
|
+
* into paragraph-length composite memories that benefit from tiered loading (L0/L1/L2).
|
|
4
|
+
*
|
|
5
|
+
* Atomistic extraction produces single-sentence facts (median ~80 chars) where
|
|
6
|
+
* L1 overviews are identical to L2 content, making tiered retrieval degenerate to
|
|
7
|
+
* flat mode. Composites bridge this gap: they join related facts into paragraph-length
|
|
8
|
+
* content that generateL1Overview() can meaningfully compress.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm: Greedy single-linkage clustering on cosine similarity of fact embeddings.
|
|
11
|
+
* Clusters with < minClusterSize members are skipped (no compression benefit).
|
|
12
|
+
*/
|
|
13
|
+
import { config } from '../config.js';
|
|
14
|
+
import { cosineSimilarity } from './embedding.js';
|
|
15
|
+
import { generateL1Overview } from './tiered-context.js';
|
|
16
|
+
/**
|
|
17
|
+
* Group facts from a single episode into composite memories by topic similarity.
|
|
18
|
+
* Returns only composites with ≥ minClusterSize members.
|
|
19
|
+
*/
|
|
20
|
+
export function buildComposites(facts) {
|
|
21
|
+
if (facts.length < config.compositeMinClusterSize)
|
|
22
|
+
return [];
|
|
23
|
+
const clusters = clusterBySimilarity(facts, config.compositeSimilarityThreshold);
|
|
24
|
+
return clusters
|
|
25
|
+
.filter((cluster) => cluster.length >= config.compositeMinClusterSize)
|
|
26
|
+
.map(synthesizeComposite);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Greedy single-linkage clustering: assign each fact to the most similar
|
|
30
|
+
* existing cluster (by centroid), or start a new cluster if below threshold.
|
|
31
|
+
*
|
|
32
|
+
* Clusters are capped at compositeMaxClusterSize to prevent "everything-bagel"
|
|
33
|
+
* composites where centroid drift causes unrelated facts to cluster together.
|
|
34
|
+
*/
|
|
35
|
+
function clusterBySimilarity(facts, threshold) {
|
|
36
|
+
const clusters = [];
|
|
37
|
+
const centroids = [];
|
|
38
|
+
const maxSize = config.compositeMaxClusterSize;
|
|
39
|
+
for (const fact of facts) {
|
|
40
|
+
let bestClusterIndex = -1;
|
|
41
|
+
let bestSimilarity = -1;
|
|
42
|
+
for (let i = 0; i < centroids.length; i++) {
|
|
43
|
+
if (clusters[i].length >= maxSize)
|
|
44
|
+
continue;
|
|
45
|
+
const sim = cosineSimilarity(fact.embedding, centroids[i]);
|
|
46
|
+
if (sim > bestSimilarity) {
|
|
47
|
+
bestSimilarity = sim;
|
|
48
|
+
bestClusterIndex = i;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (bestClusterIndex >= 0 && bestSimilarity >= threshold) {
|
|
52
|
+
clusters[bestClusterIndex].push(fact);
|
|
53
|
+
centroids[bestClusterIndex] = computeCentroid(clusters[bestClusterIndex]);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
clusters.push([fact]);
|
|
57
|
+
centroids.push([...fact.embedding]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return clusters;
|
|
61
|
+
}
|
|
62
|
+
/** Synthesize a composite memory from a cluster of related facts. */
|
|
63
|
+
function synthesizeComposite(cluster) {
|
|
64
|
+
const sorted = [...cluster].sort((a, b) => b.importance - a.importance);
|
|
65
|
+
const content = sorted.map((f) => f.content).join(' ');
|
|
66
|
+
const headline = sorted[0].headline;
|
|
67
|
+
const overview = generateL1Overview(content);
|
|
68
|
+
const embedding = computeCentroid(cluster);
|
|
69
|
+
const importance = Math.max(...cluster.map((f) => f.importance));
|
|
70
|
+
const keywords = deduplicateKeywords(cluster.flatMap((f) => f.keywords));
|
|
71
|
+
const memberMemoryIds = cluster.map((f) => f.memoryId);
|
|
72
|
+
return {
|
|
73
|
+
content,
|
|
74
|
+
headline,
|
|
75
|
+
overview: overview !== content ? overview : '',
|
|
76
|
+
embedding,
|
|
77
|
+
importance,
|
|
78
|
+
keywords,
|
|
79
|
+
memberMemoryIds,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Compute the centroid (element-wise mean) of a set of embeddings. */
|
|
83
|
+
function computeCentroid(facts) {
|
|
84
|
+
if (facts.length === 0)
|
|
85
|
+
return [];
|
|
86
|
+
const dim = facts[0].embedding.length;
|
|
87
|
+
const sum = new Float64Array(dim);
|
|
88
|
+
for (const fact of facts) {
|
|
89
|
+
for (let i = 0; i < dim; i++) {
|
|
90
|
+
sum[i] += fact.embedding[i];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const centroid = new Array(dim);
|
|
94
|
+
for (let i = 0; i < dim; i++) {
|
|
95
|
+
centroid[i] = sum[i] / facts.length;
|
|
96
|
+
}
|
|
97
|
+
return centroid;
|
|
98
|
+
}
|
|
99
|
+
/** Deduplicate keywords preserving original casing of first occurrence. */
|
|
100
|
+
function deduplicateKeywords(keywords) {
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
const result = [];
|
|
103
|
+
for (const kw of keywords) {
|
|
104
|
+
const lower = kw.toLowerCase();
|
|
105
|
+
if (!seen.has(lower)) {
|
|
106
|
+
seen.add(lower);
|
|
107
|
+
result.push(kw);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite staleness filtering for retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 policy from the composite-vs-atomic retrieval contract:
|
|
5
|
+
* exclude composites from default retrieval if any covered member memory is no
|
|
6
|
+
* longer active. This catches superseded members (expired), invalidated or
|
|
7
|
+
* deleted members, and dangling member IDs left behind after deletes.
|
|
8
|
+
*/
|
|
9
|
+
import type { SearchResult } from '../db/repository-types.js';
|
|
10
|
+
interface MemoryLookup {
|
|
11
|
+
getMemory(id: string, userId: string): Promise<{
|
|
12
|
+
id: string;
|
|
13
|
+
} | null>;
|
|
14
|
+
}
|
|
15
|
+
export interface CompositeStalenessResult {
|
|
16
|
+
filtered: SearchResult[];
|
|
17
|
+
removedCompositeIds: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function excludeStaleComposites(repo: MemoryLookup, userId: string, memories: SearchResult[]): Promise<CompositeStalenessResult>;
|
|
20
|
+
export {};
|