@steno-ai/engine 0.1.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/dist/adapters/cache.d.ts +9 -0
- package/dist/adapters/cache.d.ts.map +1 -0
- package/dist/adapters/cache.js +2 -0
- package/dist/adapters/cache.js.map +1 -0
- package/dist/adapters/embedding.d.ts +7 -0
- package/dist/adapters/embedding.d.ts.map +1 -0
- package/dist/adapters/embedding.js +2 -0
- package/dist/adapters/embedding.js.map +1 -0
- package/dist/adapters/gemini-embedding.d.ts +18 -0
- package/dist/adapters/gemini-embedding.d.ts.map +1 -0
- package/dist/adapters/gemini-embedding.js +53 -0
- package/dist/adapters/gemini-embedding.js.map +1 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/llm.d.ts +19 -0
- package/dist/adapters/llm.d.ts.map +1 -0
- package/dist/adapters/llm.js +2 -0
- package/dist/adapters/llm.js.map +1 -0
- package/dist/adapters/perplexity-embedding.d.ts +24 -0
- package/dist/adapters/perplexity-embedding.d.ts.map +1 -0
- package/dist/adapters/perplexity-embedding.js +78 -0
- package/dist/adapters/perplexity-embedding.js.map +1 -0
- package/dist/adapters/storage.d.ts +172 -0
- package/dist/adapters/storage.d.ts.map +1 -0
- package/dist/adapters/storage.js +2 -0
- package/dist/adapters/storage.js.map +1 -0
- package/dist/auth/api-key.d.ts +8 -0
- package/dist/auth/api-key.d.ts.map +1 -0
- package/dist/auth/api-key.js +27 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/config.d.ts +296 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +92 -0
- package/dist/config.js.map +1 -0
- package/dist/extraction/contradiction.d.ts +15 -0
- package/dist/extraction/contradiction.d.ts.map +1 -0
- package/dist/extraction/contradiction.js +23 -0
- package/dist/extraction/contradiction.js.map +1 -0
- package/dist/extraction/dedup.d.ts +12 -0
- package/dist/extraction/dedup.d.ts.map +1 -0
- package/dist/extraction/dedup.js +93 -0
- package/dist/extraction/dedup.js.map +1 -0
- package/dist/extraction/entity-extractor.d.ts +30 -0
- package/dist/extraction/entity-extractor.d.ts.map +1 -0
- package/dist/extraction/entity-extractor.js +145 -0
- package/dist/extraction/entity-extractor.js.map +1 -0
- package/dist/extraction/hasher.d.ts +5 -0
- package/dist/extraction/hasher.d.ts.map +1 -0
- package/dist/extraction/hasher.js +8 -0
- package/dist/extraction/hasher.js.map +1 -0
- package/dist/extraction/heuristic.d.ts +3 -0
- package/dist/extraction/heuristic.d.ts.map +1 -0
- package/dist/extraction/heuristic.js +282 -0
- package/dist/extraction/heuristic.js.map +1 -0
- package/dist/extraction/index.d.ts +10 -0
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/index.js +10 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/extraction/llm-extractor.d.ts +23 -0
- package/dist/extraction/llm-extractor.d.ts.map +1 -0
- package/dist/extraction/llm-extractor.js +238 -0
- package/dist/extraction/llm-extractor.js.map +1 -0
- package/dist/extraction/pipeline.d.ts +30 -0
- package/dist/extraction/pipeline.d.ts.map +1 -0
- package/dist/extraction/pipeline.js +398 -0
- package/dist/extraction/pipeline.js.map +1 -0
- package/dist/extraction/prompts.d.ts +28 -0
- package/dist/extraction/prompts.d.ts.map +1 -0
- package/dist/extraction/prompts.js +196 -0
- package/dist/extraction/prompts.js.map +1 -0
- package/dist/extraction/sliding-window.d.ts +41 -0
- package/dist/extraction/sliding-window.d.ts.map +1 -0
- package/dist/extraction/sliding-window.js +84 -0
- package/dist/extraction/sliding-window.js.map +1 -0
- package/dist/extraction/types.d.ts +80 -0
- package/dist/extraction/types.d.ts.map +1 -0
- package/dist/extraction/types.js +2 -0
- package/dist/extraction/types.js.map +1 -0
- package/dist/feedback/index.d.ts +2 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +2 -0
- package/dist/feedback/index.js.map +1 -0
- package/dist/feedback/tracker.d.ts +25 -0
- package/dist/feedback/tracker.d.ts.map +1 -0
- package/dist/feedback/tracker.js +90 -0
- package/dist/feedback/tracker.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/models/api-key.d.ts +54 -0
- package/dist/models/api-key.d.ts.map +1 -0
- package/dist/models/api-key.js +21 -0
- package/dist/models/api-key.js.map +1 -0
- package/dist/models/edge.d.ts +78 -0
- package/dist/models/edge.d.ts.map +1 -0
- package/dist/models/edge.js +29 -0
- package/dist/models/edge.js.map +1 -0
- package/dist/models/entity.d.ts +60 -0
- package/dist/models/entity.d.ts.map +1 -0
- package/dist/models/entity.js +22 -0
- package/dist/models/entity.js.map +1 -0
- package/dist/models/extraction.d.ts +111 -0
- package/dist/models/extraction.d.ts.map +1 -0
- package/dist/models/extraction.js +40 -0
- package/dist/models/extraction.js.map +1 -0
- package/dist/models/fact-entity.d.ts +33 -0
- package/dist/models/fact-entity.d.ts.map +1 -0
- package/dist/models/fact-entity.js +14 -0
- package/dist/models/fact-entity.js.map +1 -0
- package/dist/models/fact.d.ts +191 -0
- package/dist/models/fact.d.ts.map +1 -0
- package/dist/models/fact.js +72 -0
- package/dist/models/fact.js.map +1 -0
- package/dist/models/index.d.ts +13 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +13 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/memory-access.d.ts +89 -0
- package/dist/models/memory-access.d.ts.map +1 -0
- package/dist/models/memory-access.js +33 -0
- package/dist/models/memory-access.js.map +1 -0
- package/dist/models/session.d.ts +60 -0
- package/dist/models/session.d.ts.map +1 -0
- package/dist/models/session.js +23 -0
- package/dist/models/session.js.map +1 -0
- package/dist/models/tenant.d.ts +448 -0
- package/dist/models/tenant.d.ts.map +1 -0
- package/dist/models/tenant.js +23 -0
- package/dist/models/tenant.js.map +1 -0
- package/dist/models/trigger.d.ts +87 -0
- package/dist/models/trigger.d.ts.map +1 -0
- package/dist/models/trigger.js +41 -0
- package/dist/models/trigger.js.map +1 -0
- package/dist/models/usage-record.d.ts +37 -0
- package/dist/models/usage-record.d.ts.map +1 -0
- package/dist/models/usage-record.js +14 -0
- package/dist/models/usage-record.js.map +1 -0
- package/dist/models/webhook.d.ts +50 -0
- package/dist/models/webhook.d.ts.map +1 -0
- package/dist/models/webhook.js +25 -0
- package/dist/models/webhook.js.map +1 -0
- package/dist/profiles/index.d.ts +3 -0
- package/dist/profiles/index.d.ts.map +1 -0
- package/dist/profiles/index.js +2 -0
- package/dist/profiles/index.js.map +1 -0
- package/dist/profiles/profile.d.ts +22 -0
- package/dist/profiles/profile.d.ts.map +1 -0
- package/dist/profiles/profile.js +59 -0
- package/dist/profiles/profile.js.map +1 -0
- package/dist/retrieval/compound-search.d.ts +13 -0
- package/dist/retrieval/compound-search.d.ts.map +1 -0
- package/dist/retrieval/compound-search.js +87 -0
- package/dist/retrieval/compound-search.js.map +1 -0
- package/dist/retrieval/contradiction-surfacer.d.ts +18 -0
- package/dist/retrieval/contradiction-surfacer.d.ts.map +1 -0
- package/dist/retrieval/contradiction-surfacer.js +64 -0
- package/dist/retrieval/contradiction-surfacer.js.map +1 -0
- package/dist/retrieval/embedding-cache.d.ts +17 -0
- package/dist/retrieval/embedding-cache.d.ts.map +1 -0
- package/dist/retrieval/embedding-cache.js +56 -0
- package/dist/retrieval/embedding-cache.js.map +1 -0
- package/dist/retrieval/fusion.d.ts +27 -0
- package/dist/retrieval/fusion.d.ts.map +1 -0
- package/dist/retrieval/fusion.js +87 -0
- package/dist/retrieval/fusion.js.map +1 -0
- package/dist/retrieval/graph-traversal.d.ts +29 -0
- package/dist/retrieval/graph-traversal.d.ts.map +1 -0
- package/dist/retrieval/graph-traversal.js +208 -0
- package/dist/retrieval/graph-traversal.js.map +1 -0
- package/dist/retrieval/index.d.ts +14 -0
- package/dist/retrieval/index.d.ts.map +1 -0
- package/dist/retrieval/index.js +13 -0
- package/dist/retrieval/index.js.map +1 -0
- package/dist/retrieval/keyword-search.d.ts +4 -0
- package/dist/retrieval/keyword-search.d.ts.map +1 -0
- package/dist/retrieval/keyword-search.js +27 -0
- package/dist/retrieval/keyword-search.js.map +1 -0
- package/dist/retrieval/query-expansion.d.ts +20 -0
- package/dist/retrieval/query-expansion.d.ts.map +1 -0
- package/dist/retrieval/query-expansion.js +76 -0
- package/dist/retrieval/query-expansion.js.map +1 -0
- package/dist/retrieval/reranker.d.ts +15 -0
- package/dist/retrieval/reranker.d.ts.map +1 -0
- package/dist/retrieval/reranker.js +47 -0
- package/dist/retrieval/reranker.js.map +1 -0
- package/dist/retrieval/salience-scorer.d.ts +15 -0
- package/dist/retrieval/salience-scorer.d.ts.map +1 -0
- package/dist/retrieval/salience-scorer.js +41 -0
- package/dist/retrieval/salience-scorer.js.map +1 -0
- package/dist/retrieval/search.d.ts +21 -0
- package/dist/retrieval/search.d.ts.map +1 -0
- package/dist/retrieval/search.js +228 -0
- package/dist/retrieval/search.js.map +1 -0
- package/dist/retrieval/temporal-scorer.d.ts +18 -0
- package/dist/retrieval/temporal-scorer.d.ts.map +1 -0
- package/dist/retrieval/temporal-scorer.js +106 -0
- package/dist/retrieval/temporal-scorer.js.map +1 -0
- package/dist/retrieval/trigger-matcher.d.ts +18 -0
- package/dist/retrieval/trigger-matcher.d.ts.map +1 -0
- package/dist/retrieval/trigger-matcher.js +134 -0
- package/dist/retrieval/trigger-matcher.js.map +1 -0
- package/dist/retrieval/types.d.ts +70 -0
- package/dist/retrieval/types.d.ts.map +1 -0
- package/dist/retrieval/types.js +9 -0
- package/dist/retrieval/types.js.map +1 -0
- package/dist/retrieval/vector-search.d.ts +5 -0
- package/dist/retrieval/vector-search.d.ts.map +1 -0
- package/dist/retrieval/vector-search.js +24 -0
- package/dist/retrieval/vector-search.js.map +1 -0
- package/dist/salience/decay.d.ts +9 -0
- package/dist/salience/decay.d.ts.map +1 -0
- package/dist/salience/decay.js +15 -0
- package/dist/salience/decay.js.map +1 -0
- package/dist/salience/index.d.ts +2 -0
- package/dist/salience/index.d.ts.map +1 -0
- package/dist/salience/index.js +2 -0
- package/dist/salience/index.js.map +1 -0
- package/dist/scratchpad/index.d.ts +2 -0
- package/dist/scratchpad/index.d.ts.map +1 -0
- package/dist/scratchpad/index.js +2 -0
- package/dist/scratchpad/index.js.map +1 -0
- package/dist/scratchpad/scratchpad.d.ts +23 -0
- package/dist/scratchpad/scratchpad.d.ts.map +1 -0
- package/dist/scratchpad/scratchpad.js +107 -0
- package/dist/scratchpad/scratchpad.js.map +1 -0
- package/dist/sessions/index.d.ts +2 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +2 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/manager.d.ts +11 -0
- package/dist/sessions/manager.d.ts.map +1 -0
- package/dist/sessions/manager.js +63 -0
- package/dist/sessions/manager.js.map +1 -0
- package/package.json +38 -0
- package/src/adapters/cache.d.ts +9 -0
- package/src/adapters/cache.d.ts.map +1 -0
- package/src/adapters/cache.js.map +1 -0
- package/src/adapters/cache.ts +8 -0
- package/src/adapters/embedding.d.ts +7 -0
- package/src/adapters/embedding.d.ts.map +1 -0
- package/src/adapters/embedding.js.map +1 -0
- package/src/adapters/embedding.ts +6 -0
- package/src/adapters/gemini-embedding.ts +67 -0
- package/src/adapters/index.ts +6 -0
- package/src/adapters/llm.d.ts +19 -0
- package/src/adapters/llm.d.ts.map +1 -0
- package/src/adapters/llm.js.map +1 -0
- package/src/adapters/llm.ts +16 -0
- package/src/adapters/perplexity-embedding.d.ts +24 -0
- package/src/adapters/perplexity-embedding.d.ts.map +1 -0
- package/src/adapters/perplexity-embedding.js.map +1 -0
- package/src/adapters/perplexity-embedding.ts +98 -0
- package/src/adapters/storage.d.ts +172 -0
- package/src/adapters/storage.d.ts.map +1 -0
- package/src/adapters/storage.js.map +1 -0
- package/src/adapters/storage.ts +187 -0
- package/src/auth/api-key.ts +33 -0
- package/src/auth/index.ts +1 -0
- package/src/config.d.ts +86 -0
- package/src/config.d.ts.map +1 -0
- package/src/config.js.map +1 -0
- package/src/config.ts +131 -0
- package/src/extraction/contradiction.d.ts +15 -0
- package/src/extraction/contradiction.d.ts.map +1 -0
- package/src/extraction/contradiction.js.map +1 -0
- package/src/extraction/contradiction.ts +33 -0
- package/src/extraction/dedup.d.ts +12 -0
- package/src/extraction/dedup.d.ts.map +1 -0
- package/src/extraction/dedup.js.map +1 -0
- package/src/extraction/dedup.ts +133 -0
- package/src/extraction/entity-extractor.d.ts +30 -0
- package/src/extraction/entity-extractor.d.ts.map +1 -0
- package/src/extraction/entity-extractor.js.map +1 -0
- package/src/extraction/entity-extractor.ts +193 -0
- package/src/extraction/hasher.d.ts +5 -0
- package/src/extraction/hasher.d.ts.map +1 -0
- package/src/extraction/hasher.js.map +1 -0
- package/src/extraction/hasher.ts +7 -0
- package/src/extraction/heuristic.d.ts +3 -0
- package/src/extraction/heuristic.d.ts.map +1 -0
- package/src/extraction/heuristic.js.map +1 -0
- package/src/extraction/heuristic.ts +341 -0
- package/src/extraction/index.ts +9 -0
- package/src/extraction/llm-extractor.d.ts +21 -0
- package/src/extraction/llm-extractor.d.ts.map +1 -0
- package/src/extraction/llm-extractor.js.map +1 -0
- package/src/extraction/llm-extractor.ts +267 -0
- package/src/extraction/pipeline.d.ts +27 -0
- package/src/extraction/pipeline.d.ts.map +1 -0
- package/src/extraction/pipeline.js.map +1 -0
- package/src/extraction/pipeline.ts +515 -0
- package/src/extraction/prompts.js.map +1 -0
- package/src/extraction/prompts.ts +233 -0
- package/src/extraction/sliding-window.d.ts +41 -0
- package/src/extraction/sliding-window.d.ts.map +1 -0
- package/src/extraction/sliding-window.js.map +1 -0
- package/src/extraction/sliding-window.ts +121 -0
- package/src/extraction/types.d.ts +68 -0
- package/src/extraction/types.d.ts.map +1 -0
- package/src/extraction/types.js.map +1 -0
- package/src/extraction/types.ts +80 -0
- package/src/feedback/index.ts +1 -0
- package/src/feedback/tracker.d.ts +25 -0
- package/src/feedback/tracker.d.ts.map +1 -0
- package/src/feedback/tracker.js.map +1 -0
- package/src/feedback/tracker.ts +119 -0
- package/src/index.ts +12 -0
- package/src/models/api-key.d.ts +54 -0
- package/src/models/api-key.d.ts.map +1 -0
- package/src/models/api-key.js.map +1 -0
- package/src/models/api-key.ts +26 -0
- package/src/models/edge.d.ts +78 -0
- package/src/models/edge.d.ts.map +1 -0
- package/src/models/edge.js.map +1 -0
- package/src/models/edge.ts +34 -0
- package/src/models/entity.d.ts +60 -0
- package/src/models/entity.d.ts.map +1 -0
- package/src/models/entity.js.map +1 -0
- package/src/models/entity.ts +27 -0
- package/src/models/extraction.d.ts +111 -0
- package/src/models/extraction.d.ts.map +1 -0
- package/src/models/extraction.js.map +1 -0
- package/src/models/extraction.ts +45 -0
- package/src/models/fact-entity.d.ts +33 -0
- package/src/models/fact-entity.d.ts.map +1 -0
- package/src/models/fact-entity.js.map +1 -0
- package/src/models/fact-entity.ts +19 -0
- package/src/models/fact.ts +85 -0
- package/src/models/index.d.ts +13 -0
- package/src/models/index.d.ts.map +1 -0
- package/src/models/index.js.map +1 -0
- package/src/models/index.ts +12 -0
- package/src/models/memory-access.d.ts +89 -0
- package/src/models/memory-access.d.ts.map +1 -0
- package/src/models/memory-access.js.map +1 -0
- package/src/models/memory-access.ts +41 -0
- package/src/models/session.d.ts +60 -0
- package/src/models/session.d.ts.map +1 -0
- package/src/models/session.js.map +1 -0
- package/src/models/session.ts +28 -0
- package/src/models/tenant.d.ts +214 -0
- package/src/models/tenant.d.ts.map +1 -0
- package/src/models/tenant.js.map +1 -0
- package/src/models/tenant.ts +28 -0
- package/src/models/trigger.d.ts +87 -0
- package/src/models/trigger.d.ts.map +1 -0
- package/src/models/trigger.js.map +1 -0
- package/src/models/trigger.ts +58 -0
- package/src/models/usage-record.d.ts +37 -0
- package/src/models/usage-record.d.ts.map +1 -0
- package/src/models/usage-record.js.map +1 -0
- package/src/models/usage-record.ts +16 -0
- package/src/models/webhook.d.ts +50 -0
- package/src/models/webhook.d.ts.map +1 -0
- package/src/models/webhook.js.map +1 -0
- package/src/models/webhook.ts +30 -0
- package/src/profiles/index.ts +2 -0
- package/src/profiles/profile.ts +81 -0
- package/src/retrieval/compound-search.d.ts +13 -0
- package/src/retrieval/compound-search.d.ts.map +1 -0
- package/src/retrieval/compound-search.js.map +1 -0
- package/src/retrieval/compound-search.ts +104 -0
- package/src/retrieval/contradiction-surfacer.d.ts +18 -0
- package/src/retrieval/contradiction-surfacer.d.ts.map +1 -0
- package/src/retrieval/contradiction-surfacer.js.map +1 -0
- package/src/retrieval/contradiction-surfacer.ts +87 -0
- package/src/retrieval/embedding-cache.d.ts +17 -0
- package/src/retrieval/embedding-cache.d.ts.map +1 -0
- package/src/retrieval/embedding-cache.js.map +1 -0
- package/src/retrieval/embedding-cache.ts +63 -0
- package/src/retrieval/fusion.d.ts +26 -0
- package/src/retrieval/fusion.d.ts.map +1 -0
- package/src/retrieval/fusion.js.map +1 -0
- package/src/retrieval/fusion.ts +129 -0
- package/src/retrieval/graph-traversal.d.ts +28 -0
- package/src/retrieval/graph-traversal.d.ts.map +1 -0
- package/src/retrieval/graph-traversal.js.map +1 -0
- package/src/retrieval/graph-traversal.ts +235 -0
- package/src/retrieval/index.ts +13 -0
- package/src/retrieval/keyword-search.ts +39 -0
- package/src/retrieval/query-expansion.d.ts +20 -0
- package/src/retrieval/query-expansion.d.ts.map +1 -0
- package/src/retrieval/query-expansion.js.map +1 -0
- package/src/retrieval/query-expansion.ts +86 -0
- package/src/retrieval/reranker.d.ts +15 -0
- package/src/retrieval/reranker.d.ts.map +1 -0
- package/src/retrieval/reranker.js.map +1 -0
- package/src/retrieval/reranker.ts +56 -0
- package/src/retrieval/salience-scorer.d.ts +15 -0
- package/src/retrieval/salience-scorer.d.ts.map +1 -0
- package/src/retrieval/salience-scorer.js.map +1 -0
- package/src/retrieval/salience-scorer.ts +57 -0
- package/src/retrieval/search.d.ts +21 -0
- package/src/retrieval/search.d.ts.map +1 -0
- package/src/retrieval/search.js.map +1 -0
- package/src/retrieval/search.ts +271 -0
- package/src/retrieval/temporal-scorer.ts +111 -0
- package/src/retrieval/trigger-matcher.d.ts +18 -0
- package/src/retrieval/trigger-matcher.d.ts.map +1 -0
- package/src/retrieval/trigger-matcher.js.map +1 -0
- package/src/retrieval/trigger-matcher.ts +180 -0
- package/src/retrieval/types.d.ts +66 -0
- package/src/retrieval/types.d.ts.map +1 -0
- package/src/retrieval/types.js.map +1 -0
- package/src/retrieval/types.ts +82 -0
- package/src/retrieval/vector-search.d.ts +5 -0
- package/src/retrieval/vector-search.d.ts.map +1 -0
- package/src/retrieval/vector-search.js.map +1 -0
- package/src/retrieval/vector-search.ts +38 -0
- package/src/salience/decay.d.ts +9 -0
- package/src/salience/decay.d.ts.map +1 -0
- package/src/salience/decay.js.map +1 -0
- package/src/salience/decay.ts +25 -0
- package/src/salience/index.ts +1 -0
- package/src/scratchpad/index.ts +1 -0
- package/src/scratchpad/scratchpad.d.ts +23 -0
- package/src/scratchpad/scratchpad.d.ts.map +1 -0
- package/src/scratchpad/scratchpad.js.map +1 -0
- package/src/scratchpad/scratchpad.ts +140 -0
- package/src/sessions/index.ts +1 -0
- package/src/sessions/manager.ts +87 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { LLMAdapter } from '../adapters/llm.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Multi-query expansion — like Hydra DB's Adaptive Query Expansion.
|
|
5
|
+
*
|
|
6
|
+
* Takes a single query and generates 3-4 semantically diverse reformulations.
|
|
7
|
+
* Each captures a different interpretation of the user's intent:
|
|
8
|
+
* - Paraphrases
|
|
9
|
+
* - Temporal concretizations ("last week" → "projects from March 18-25")
|
|
10
|
+
* - Domain-specific restatements
|
|
11
|
+
*
|
|
12
|
+
* All expanded queries are searched in parallel for higher recall.
|
|
13
|
+
*/
|
|
14
|
+
export async function expandQuery(
|
|
15
|
+
llm: LLMAdapter,
|
|
16
|
+
query: string,
|
|
17
|
+
): Promise<string[]> {
|
|
18
|
+
// Short queries or very specific ones don't need expansion
|
|
19
|
+
if (query.length < 15 || query.split(' ').length <= 3) {
|
|
20
|
+
return [query];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const response = await llm.complete([
|
|
25
|
+
{
|
|
26
|
+
role: 'system',
|
|
27
|
+
content: `You generate search query expansions for a memory retrieval system. Given a user query, produce 3 alternative phrasings that capture different aspects of the intent.
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
- Each alternative should use different keywords/phrasing
|
|
31
|
+
- Include temporal concretizations if relevant ("recently" → "in the past week")
|
|
32
|
+
- Include domain-specific restatements
|
|
33
|
+
- Keep each alternative concise (under 15 words)
|
|
34
|
+
- Return ONLY a JSON array of strings: ["query1", "query2", "query3"]`,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
role: 'user',
|
|
38
|
+
content: query,
|
|
39
|
+
},
|
|
40
|
+
], { temperature: 0.3, responseFormat: 'json' });
|
|
41
|
+
|
|
42
|
+
const parsed = JSON.parse(response.content);
|
|
43
|
+
const expansions = Array.isArray(parsed)
|
|
44
|
+
? parsed.filter((q): q is string => typeof q === 'string' && q.trim().length > 0)
|
|
45
|
+
: [];
|
|
46
|
+
|
|
47
|
+
// Always include the original query first
|
|
48
|
+
return [query, ...expansions.slice(0, 3)];
|
|
49
|
+
} catch {
|
|
50
|
+
// If expansion fails, just use the original query
|
|
51
|
+
return [query];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Fast heuristic expansion — no LLM needed.
|
|
57
|
+
* Generates simple reformulations using string manipulation.
|
|
58
|
+
* Use this when you don't have an LLM available or want zero latency.
|
|
59
|
+
*/
|
|
60
|
+
export function expandQueryHeuristic(query: string): string[] {
|
|
61
|
+
const queries = [query];
|
|
62
|
+
const lower = query.toLowerCase();
|
|
63
|
+
|
|
64
|
+
// Add "User" prefix version if not present
|
|
65
|
+
if (!lower.startsWith('user') && !lower.includes('my ') && !lower.includes('i ')) {
|
|
66
|
+
queries.push(`User ${lower}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Convert "my X" to "user's X"
|
|
70
|
+
if (lower.includes('my ')) {
|
|
71
|
+
queries.push(lower.replace(/\bmy\b/g, "user's"));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Convert questions to statements
|
|
75
|
+
if (lower.startsWith('what ') || lower.startsWith('who ') || lower.startsWith('where ') || lower.startsWith('when ')) {
|
|
76
|
+
const statement = lower
|
|
77
|
+
.replace(/^what (is|are|was|were) /, '')
|
|
78
|
+
.replace(/^who (is|are|was|were) /, '')
|
|
79
|
+
.replace(/^where (is|are|was|were|does|did) /, '')
|
|
80
|
+
.replace(/^when (did|does|was|were|is) /, '')
|
|
81
|
+
.replace(/\?$/, '');
|
|
82
|
+
if (statement !== lower) queries.push(statement);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return queries.slice(0, 4);
|
|
86
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EmbeddingAdapter } from '../adapters/embedding.js';
|
|
2
|
+
import type { SearchResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Re-rank search results using embedding cosine similarity.
|
|
5
|
+
* Deterministic, free (uses existing embedding model), no LLM call.
|
|
6
|
+
*
|
|
7
|
+
* How it works:
|
|
8
|
+
* 1. Embed the query
|
|
9
|
+
* 2. Embed all fact content texts in a single batch call
|
|
10
|
+
* 3. Compute cosine similarity between query embedding and each fact embedding
|
|
11
|
+
* 4. Blend the similarity score with the original fusion score
|
|
12
|
+
* 5. Re-sort by blended score
|
|
13
|
+
*/
|
|
14
|
+
export declare function rerank(embedding: EmbeddingAdapter, query: string, results: SearchResult[], topK?: number): Promise<SearchResult[]>;
|
|
15
|
+
//# sourceMappingURL=reranker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reranker.d.ts","sourceRoot":"","sources":["reranker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,wBAAsB,MAAM,CAC1B,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,EAAE,EACvB,IAAI,GAAE,MAAW,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAsBzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reranker.js","sourceRoot":"","sources":["reranker.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,SAA2B,EAC3B,KAAa,EACb,OAAuB,EACvB,OAAe,EAAE;IAEjB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC;IAExC,4CAA4C;IAC5C,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;IACtC,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE3C,wDAAwD;IACxD,MAAM,aAAa,GAAG,GAAG,CAAC,CAAC,sDAAsD;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,WAAW,GAAG,gBAAgB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAE,CAAC,CAAC;QACzE,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,GAAG,WAAW,GAAG,aAAa,CAAC;QACjF,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,wBAAwB;IACxB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAEzC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAW,EAAE,CAAW;IAChD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QAC5B,KAAK,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACvB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACzB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { EmbeddingAdapter } from '../adapters/embedding.js';
|
|
2
|
+
import type { SearchResult } from './types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Re-rank search results using embedding cosine similarity.
|
|
6
|
+
* Deterministic, free (uses existing embedding model), no LLM call.
|
|
7
|
+
*
|
|
8
|
+
* How it works:
|
|
9
|
+
* 1. Embed the query
|
|
10
|
+
* 2. Embed all fact content texts in a single batch call
|
|
11
|
+
* 3. Compute cosine similarity between query embedding and each fact embedding
|
|
12
|
+
* 4. Blend the similarity score with the original fusion score
|
|
13
|
+
* 5. Re-sort by blended score
|
|
14
|
+
*/
|
|
15
|
+
export async function rerank(
|
|
16
|
+
embedding: EmbeddingAdapter,
|
|
17
|
+
query: string,
|
|
18
|
+
results: SearchResult[],
|
|
19
|
+
topK: number = 10,
|
|
20
|
+
): Promise<SearchResult[]> {
|
|
21
|
+
if (results.length === 0) return [];
|
|
22
|
+
if (results.length <= 1) return results;
|
|
23
|
+
|
|
24
|
+
// Embed query + all fact texts in one batch
|
|
25
|
+
const texts = [query, ...results.map(r => r.fact.content)];
|
|
26
|
+
const embeddings = await embedding.embedBatch(texts);
|
|
27
|
+
const queryEmbedding = embeddings[0]!;
|
|
28
|
+
const factEmbeddings = embeddings.slice(1);
|
|
29
|
+
|
|
30
|
+
// Score each result by cosine similarity with the query
|
|
31
|
+
const RERANK_WEIGHT = 0.4; // 40% embedding similarity, 60% original fusion score
|
|
32
|
+
const scored = results.map((r, i) => {
|
|
33
|
+
const rerankScore = cosineSimilarity(queryEmbedding, factEmbeddings[i]!);
|
|
34
|
+
const blendedScore = r.score * (1 - RERANK_WEIGHT) + rerankScore * RERANK_WEIGHT;
|
|
35
|
+
return { ...r, score: blendedScore };
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Sort by blended score
|
|
39
|
+
scored.sort((a, b) => b.score - a.score);
|
|
40
|
+
|
|
41
|
+
return scored.slice(0, topK);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function cosineSimilarity(a: number[], b: number[]): number {
|
|
45
|
+
if (a.length !== b.length || a.length === 0) return 0;
|
|
46
|
+
let dotProduct = 0;
|
|
47
|
+
let normA = 0;
|
|
48
|
+
let normB = 0;
|
|
49
|
+
for (let i = 0; i < a.length; i++) {
|
|
50
|
+
dotProduct += a[i]! * b[i]!;
|
|
51
|
+
normA += a[i]! * a[i]!;
|
|
52
|
+
normB += b[i]! * b[i]!;
|
|
53
|
+
}
|
|
54
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
55
|
+
return denom === 0 ? 0 : dotProduct / denom;
|
|
56
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Candidate } from './types.js';
|
|
2
|
+
export interface SalienceConfig {
|
|
3
|
+
halfLifeDays: number;
|
|
4
|
+
normalizationK: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Score all candidates with recency and salience signals.
|
|
8
|
+
*
|
|
9
|
+
* recencyScore = pure time decay (how recently the fact was accessed)
|
|
10
|
+
* salienceScore = importance x frequency factor (how important and reinforced)
|
|
11
|
+
*
|
|
12
|
+
* These are separate signals that feed into fusion with independent weights.
|
|
13
|
+
*/
|
|
14
|
+
export declare function scoreSalience(candidates: Candidate[], config?: Partial<SalienceConfig>): Candidate[];
|
|
15
|
+
//# sourceMappingURL=salience-scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salience-scorer.d.ts","sourceRoot":"","sources":["salience-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,SAAS,EAAE,CAsCb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salience-scorer.js","sourceRoot":"","sources":["salience-scorer.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAuB,EACvB,MAAgC;IAEhC,MAAM,YAAY,GAAG,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;IAChD,MAAM,cAAc,GAAG,MAAM,EAAE,cAAc,IAAI,EAAE,CAAC;IAEpD,OAAO,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QAChC,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;QAE3B,sDAAsD;QACtD,sEAAsE;QACtE,mEAAmE;QACnE,mEAAmE;QACnE,0CAA0C;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;QAEvC,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY;YACvC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YAC9E,CAAC,CAAC,QAAQ,CAAC;QACb,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAElF,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS;YACtC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YAC3E,CAAC,CAAC,QAAQ,CAAC;QACb,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnF,mDAAmD;QACnD,MAAM,YAAY,GAAG,GAAG,GAAG,aAAa,GAAG,GAAG,GAAG,eAAe,CAAC;QAEjE,0CAA0C;QAC1C,kFAAkF;QAClF,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;QACnG,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC;QAExD,OAAO;YACL,GAAG,SAAS;YACZ,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YACpD,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;SACvD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Candidate } from './types.js';
|
|
2
|
+
|
|
3
|
+
export interface SalienceConfig {
|
|
4
|
+
halfLifeDays: number; // default 30
|
|
5
|
+
normalizationK: number; // default 50
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Score all candidates with recency and salience signals.
|
|
10
|
+
*
|
|
11
|
+
* recencyScore = pure time decay (how recently the fact was accessed)
|
|
12
|
+
* salienceScore = importance x frequency factor (how important and reinforced)
|
|
13
|
+
*
|
|
14
|
+
* These are separate signals that feed into fusion with independent weights.
|
|
15
|
+
*/
|
|
16
|
+
export function scoreSalience(
|
|
17
|
+
candidates: Candidate[],
|
|
18
|
+
config?: Partial<SalienceConfig>,
|
|
19
|
+
): Candidate[] {
|
|
20
|
+
const halfLifeDays = config?.halfLifeDays ?? 30;
|
|
21
|
+
const normalizationK = config?.normalizationK ?? 50;
|
|
22
|
+
|
|
23
|
+
return candidates.map(candidate => {
|
|
24
|
+
const { fact } = candidate;
|
|
25
|
+
|
|
26
|
+
// Recency: blend of access recency + creation recency
|
|
27
|
+
// Access recency = how recently the fact was recalled (reinforcement)
|
|
28
|
+
// Creation recency = how recently the fact was created (freshness)
|
|
29
|
+
// Git-style versioning needs creation recency so newer versions of
|
|
30
|
+
// the same lineage naturally rank higher.
|
|
31
|
+
const lambda = Math.LN2 / halfLifeDays;
|
|
32
|
+
|
|
33
|
+
const daysSinceAccess = fact.lastAccessed
|
|
34
|
+
? (Date.now() - new Date(fact.lastAccessed).getTime()) / (1000 * 60 * 60 * 24)
|
|
35
|
+
: Infinity;
|
|
36
|
+
const accessRecency = fact.lastAccessed ? Math.exp(-lambda * daysSinceAccess) : 0;
|
|
37
|
+
|
|
38
|
+
const daysSinceCreation = fact.createdAt
|
|
39
|
+
? (Date.now() - new Date(fact.createdAt).getTime()) / (1000 * 60 * 60 * 24)
|
|
40
|
+
: Infinity;
|
|
41
|
+
const creationRecency = fact.createdAt ? Math.exp(-lambda * daysSinceCreation) : 0;
|
|
42
|
+
|
|
43
|
+
// Blend: 50% access recency + 50% creation recency
|
|
44
|
+
const recencyScore = 0.5 * accessRecency + 0.5 * creationRecency;
|
|
45
|
+
|
|
46
|
+
// Salience: importance x frequency factor
|
|
47
|
+
// This captures "how important is this fact AND how often has it been reinforced"
|
|
48
|
+
const frequencyFactor = Math.min(1.0, Math.log(1 + fact.frequency) / Math.log(1 + normalizationK));
|
|
49
|
+
const salienceScore = fact.importance * frequencyFactor;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
...candidate,
|
|
53
|
+
recencyScore: Math.max(0, Math.min(1, recencyScore)),
|
|
54
|
+
salienceScore: Math.max(0, Math.min(1, salienceScore)),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StorageAdapter } from '../adapters/storage.js';
|
|
2
|
+
import type { EmbeddingAdapter } from '../adapters/embedding.js';
|
|
3
|
+
import type { CacheAdapter } from '../adapters/cache.js';
|
|
4
|
+
import type { LLMAdapter } from '../adapters/llm.js';
|
|
5
|
+
import type { SearchOptions, SearchResponse, FusionWeights } from './types.js';
|
|
6
|
+
export interface SearchConfig {
|
|
7
|
+
storage: StorageAdapter;
|
|
8
|
+
embedding: EmbeddingAdapter;
|
|
9
|
+
cache?: CacheAdapter;
|
|
10
|
+
defaultWeights?: FusionWeights;
|
|
11
|
+
salienceHalfLifeDays?: number;
|
|
12
|
+
salienceNormalizationK?: number;
|
|
13
|
+
graphMaxDepth?: number;
|
|
14
|
+
graphMaxEntities?: number;
|
|
15
|
+
rerankerLLM?: LLMAdapter;
|
|
16
|
+
rerank?: boolean;
|
|
17
|
+
/** LLM for query expansion (optional — falls back to heuristic expansion) */
|
|
18
|
+
expansionLLM?: LLMAdapter;
|
|
19
|
+
}
|
|
20
|
+
export declare function search(config: SearchConfig, options: SearchOptions): Promise<SearchResponse>;
|
|
21
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAa,MAAM,YAAY,CAAC;AAa1F,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC;CAC3B;AAED,wBAAsB,MAAM,CAC1B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,cAAc,CAAC,CA0KzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import type { StorageAdapter } from '../adapters/storage.js';
|
|
2
|
+
import type { EmbeddingAdapter } from '../adapters/embedding.js';
|
|
3
|
+
import type { CacheAdapter } from '../adapters/cache.js';
|
|
4
|
+
import type { LLMAdapter } from '../adapters/llm.js';
|
|
5
|
+
import type { SearchOptions, SearchResponse, FusionWeights, Candidate } from './types.js';
|
|
6
|
+
import { DEFAULT_FUSION_WEIGHTS } from './types.js';
|
|
7
|
+
import { compoundSearchSignal } from './compound-search.js';
|
|
8
|
+
import { graphSearch } from './graph-traversal.js';
|
|
9
|
+
import { matchTriggers } from './trigger-matcher.js';
|
|
10
|
+
import { scoreSalience } from './salience-scorer.js';
|
|
11
|
+
import { fuseAndRank } from './fusion.js';
|
|
12
|
+
import { surfaceContradictions } from './contradiction-surfacer.js';
|
|
13
|
+
import { recordAccesses } from '../feedback/tracker.js';
|
|
14
|
+
import { CachedEmbeddingAdapter } from './embedding-cache.js';
|
|
15
|
+
import { rerank } from './reranker.js';
|
|
16
|
+
import { expandQueryHeuristic } from './query-expansion.js';
|
|
17
|
+
import { extractTimeReference, scoreTemporalRelevance } from './temporal-scorer.js';
|
|
18
|
+
|
|
19
|
+
export interface SearchConfig {
|
|
20
|
+
storage: StorageAdapter;
|
|
21
|
+
embedding: EmbeddingAdapter;
|
|
22
|
+
cache?: CacheAdapter; // if provided, wraps embedding with cache
|
|
23
|
+
defaultWeights?: FusionWeights;
|
|
24
|
+
salienceHalfLifeDays?: number;
|
|
25
|
+
salienceNormalizationK?: number;
|
|
26
|
+
graphMaxDepth?: number;
|
|
27
|
+
graphMaxEntities?: number;
|
|
28
|
+
rerankerLLM?: LLMAdapter; // Deprecated — use embedding-based reranking instead
|
|
29
|
+
rerank?: boolean; // If true, re-ranks results using embedding similarity (deterministic, free)
|
|
30
|
+
/** LLM for query expansion (optional — falls back to heuristic expansion) */
|
|
31
|
+
expansionLLM?: LLMAdapter;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function search(
|
|
35
|
+
config: SearchConfig,
|
|
36
|
+
options: SearchOptions,
|
|
37
|
+
): Promise<SearchResponse> {
|
|
38
|
+
const startTime = Date.now();
|
|
39
|
+
const limit = Math.min(options.limit ?? 10, 100);
|
|
40
|
+
const weights = options.weights ?? config.defaultWeights ?? DEFAULT_FUSION_WEIGHTS;
|
|
41
|
+
const fetchMultiplier = 3; // fetch 3x limit from each signal for better fusion
|
|
42
|
+
|
|
43
|
+
// Wrap embedding with cache if available
|
|
44
|
+
const effectiveEmbedding = config.cache
|
|
45
|
+
? new CachedEmbeddingAdapter(config.embedding, config.cache)
|
|
46
|
+
: config.embedding;
|
|
47
|
+
|
|
48
|
+
// 1. Run all signals in PARALLEL — ONE compound search (not multiple)
|
|
49
|
+
// Multi-query expansion adds latency (3× embedding calls). Instead:
|
|
50
|
+
// - Single compound search with original query (vector + keyword in 1 DB call)
|
|
51
|
+
// - Graph search with original query
|
|
52
|
+
// - Trigger matching
|
|
53
|
+
// All parallel = single round trip time.
|
|
54
|
+
const t0 = Date.now();
|
|
55
|
+
|
|
56
|
+
const tCompound = Date.now();
|
|
57
|
+
const compoundPromise = compoundSearchSignal(config.storage, effectiveEmbedding, options.query, options.tenantId, options.scope, options.scopeId, limit * fetchMultiplier).catch(() => ({ vectorCandidates: [] as Candidate[], keywordCandidates: [] as Candidate[] }));
|
|
58
|
+
const tGraph = Date.now();
|
|
59
|
+
const graphPromise = graphSearch(config.storage, effectiveEmbedding, options.query, options.tenantId, options.scope, options.scopeId, limit * fetchMultiplier, { maxDepth: config.graphMaxDepth, maxEntities: config.graphMaxEntities, asOf: options.temporalFilter?.asOf }).catch(() => [] as Candidate[]);
|
|
60
|
+
const tTrigger = Date.now();
|
|
61
|
+
const triggerPromise = matchTriggers(config.storage, effectiveEmbedding, options.query, options.tenantId, options.scope, options.scopeId).catch(() => ({ candidates: [] as Candidate[], triggersMatched: [] as string[] }));
|
|
62
|
+
|
|
63
|
+
const [compoundResult, graphSettled, triggerSettled] = await Promise.all([
|
|
64
|
+
compoundPromise.then(r => { console.error(`[steno-search] compound: ${Date.now() - tCompound}ms (vec=${r.vectorCandidates.length}, kw=${r.keywordCandidates.length})`); return r; }),
|
|
65
|
+
graphPromise.then(r => { console.error(`[steno-search] graph: ${Date.now() - tGraph}ms (${Array.isArray(r) ? r.length : 0} candidates)`); return r; }),
|
|
66
|
+
triggerPromise.then(r => { console.error(`[steno-search] trigger: ${Date.now() - tTrigger}ms`); return r; }),
|
|
67
|
+
]);
|
|
68
|
+
console.error(`[steno-search] Signals total: ${Date.now() - t0}ms`);
|
|
69
|
+
|
|
70
|
+
const vectorCandidates = compoundResult.vectorCandidates;
|
|
71
|
+
const keywordCandidates = compoundResult.keywordCandidates;
|
|
72
|
+
const graphCandidates = Array.isArray(graphSettled) ? graphSettled : [];
|
|
73
|
+
const triggerResult = triggerSettled;
|
|
74
|
+
const triggersMatched = triggerResult.triggersMatched;
|
|
75
|
+
|
|
76
|
+
// 2. Triple-tier pre-fusion reranking — rerank each stream INDEPENDENTLY
|
|
77
|
+
// Only rerank when there are enough candidates to justify the embedding cost
|
|
78
|
+
// before fusion, like Hydra DB's triple-tier architecture.
|
|
79
|
+
const t1 = Date.now();
|
|
80
|
+
|
|
81
|
+
// Batch-embed query + all unique candidate contents in ONE call
|
|
82
|
+
const allPreRerankCandidates = [...vectorCandidates, ...graphCandidates];
|
|
83
|
+
let queryEmbedding: number[] | null = null;
|
|
84
|
+
const candidateEmbeddings = new Map<string, number[]>();
|
|
85
|
+
|
|
86
|
+
// Only rerank if we have >10 candidates — for small sets the original order is fine
|
|
87
|
+
if (allPreRerankCandidates.length > 10) {
|
|
88
|
+
try {
|
|
89
|
+
const uniqueTexts = new Map<string, string>();
|
|
90
|
+
for (const c of allPreRerankCandidates) {
|
|
91
|
+
if (!uniqueTexts.has(c.fact.id)) uniqueTexts.set(c.fact.id, c.fact.content);
|
|
92
|
+
}
|
|
93
|
+
const textsToEmbed = [options.query, ...uniqueTexts.values()];
|
|
94
|
+
const embeddings = await effectiveEmbedding.embedBatch(textsToEmbed);
|
|
95
|
+
queryEmbedding = embeddings[0]!;
|
|
96
|
+
let idx = 1;
|
|
97
|
+
for (const [factId] of uniqueTexts) {
|
|
98
|
+
candidateEmbeddings.set(factId, embeddings[idx++]!);
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// Reranking fails silently — proceed without it
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Rerank vector candidates
|
|
106
|
+
if (queryEmbedding && vectorCandidates.length > 1) {
|
|
107
|
+
const RERANK_W = 0.4;
|
|
108
|
+
for (const c of vectorCandidates) {
|
|
109
|
+
const factEmb = candidateEmbeddings.get(c.fact.id);
|
|
110
|
+
if (factEmb) {
|
|
111
|
+
const sim = cosineSim(queryEmbedding, factEmb);
|
|
112
|
+
c.vectorScore = c.vectorScore * (1 - RERANK_W) + sim * RERANK_W;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
vectorCandidates.sort((a, b) => b.vectorScore - a.vectorScore);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Rerank graph candidates
|
|
119
|
+
if (queryEmbedding && graphCandidates.length > 1) {
|
|
120
|
+
const RERANK_W = 0.4;
|
|
121
|
+
for (const c of graphCandidates) {
|
|
122
|
+
const factEmb = candidateEmbeddings.get(c.fact.id);
|
|
123
|
+
if (factEmb) {
|
|
124
|
+
const sim = cosineSim(queryEmbedding, factEmb);
|
|
125
|
+
c.graphScore = c.graphScore * (1 - RERANK_W) + sim * RERANK_W;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
graphCandidates.sort((a, b) => b.graphScore - a.graphScore);
|
|
129
|
+
}
|
|
130
|
+
// Keyword candidates skip reranking — FTS scores shouldn't be overridden by embeddings
|
|
131
|
+
console.error(`[steno-search] Pre-fusion rerank: ${Date.now() - t1}ms`);
|
|
132
|
+
|
|
133
|
+
// 3. Merge all pre-reranked streams
|
|
134
|
+
const allCandidates: Candidate[] = [
|
|
135
|
+
...vectorCandidates,
|
|
136
|
+
...keywordCandidates,
|
|
137
|
+
...graphCandidates,
|
|
138
|
+
...triggerResult.candidates,
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
if (allCandidates.length === 0) {
|
|
142
|
+
return {
|
|
143
|
+
results: [],
|
|
144
|
+
triggersMatched,
|
|
145
|
+
totalCandidates: 0,
|
|
146
|
+
durationMs: Date.now() - startTime,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 4. Score salience + recency on all candidates
|
|
151
|
+
const scoredCandidates = scoreSalience(allCandidates, {
|
|
152
|
+
halfLifeDays: config.salienceHalfLifeDays,
|
|
153
|
+
normalizationK: config.salienceNormalizationK,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// 4b. Score temporal relevance if query has time reference
|
|
157
|
+
const timeRef = extractTimeReference(options.query);
|
|
158
|
+
if (timeRef) {
|
|
159
|
+
scoreTemporalRelevance(scoredCandidates, timeRef);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 5. Fuse and rank
|
|
163
|
+
const fusionResults = fuseAndRank(scoredCandidates, weights, limit);
|
|
164
|
+
|
|
165
|
+
// 5b. Lineage dedup — keep only the NEWEST version per lineage
|
|
166
|
+
// Git-style append-only means multiple versions coexist. For normal queries,
|
|
167
|
+
// show only the latest version (by createdAt). For "includeHistory", show all.
|
|
168
|
+
let dedupedResults = fusionResults;
|
|
169
|
+
if (!options.includeHistory) {
|
|
170
|
+
const lineageBest = new Map<string, { idx: number; createdAt: Date; score: number }>();
|
|
171
|
+
for (let i = 0; i < fusionResults.length; i++) {
|
|
172
|
+
const r = fusionResults[i]!;
|
|
173
|
+
const lid = r.fact.lineageId;
|
|
174
|
+
if (!lid) continue;
|
|
175
|
+
const existing = lineageBest.get(lid);
|
|
176
|
+
const createdAt = new Date(r.fact.createdAt);
|
|
177
|
+
if (!existing || createdAt > existing.createdAt) {
|
|
178
|
+
lineageBest.set(lid, { idx: i, createdAt, score: r.score });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const keepIndices = new Set(Array.from(lineageBest.values()).map(v => v.idx));
|
|
182
|
+
// Also keep facts with no lineage match (unique facts)
|
|
183
|
+
dedupedResults = fusionResults.filter((r, idx) => {
|
|
184
|
+
const lid = r.fact.lineageId;
|
|
185
|
+
if (!lid) return true;
|
|
186
|
+
return keepIndices.has(idx);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 5c. Knowledge chain resolution — if a result has metadata.relationType === 'updates',
|
|
191
|
+
// check if the fact it updates is ALSO in results. If so, suppress the older one.
|
|
192
|
+
const updatedFactIds = new Set<string>();
|
|
193
|
+
for (const r of dedupedResults) {
|
|
194
|
+
const meta = r.fact.metadata as Record<string, unknown> | undefined;
|
|
195
|
+
if (meta?.relationType === 'updates' && meta?.relatedFactId) {
|
|
196
|
+
updatedFactIds.add(meta.relatedFactId as string);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (updatedFactIds.size > 0) {
|
|
200
|
+
dedupedResults = dedupedResults.filter(r => !updatedFactIds.has(r.fact.id));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 5d. Token budget trimming — keep highest-scored results that fit within budget
|
|
204
|
+
if (options.tokenBudget && options.tokenBudget > 0) {
|
|
205
|
+
let tokenCount = 0;
|
|
206
|
+
const budgetResults: typeof dedupedResults = [];
|
|
207
|
+
for (const r of dedupedResults) {
|
|
208
|
+
// Rough token estimate: content chars / 4, plus sourceChunk if present
|
|
209
|
+
const factTokens = Math.ceil(r.fact.content.length / 4) +
|
|
210
|
+
(r.fact.sourceChunk ? Math.ceil(r.fact.sourceChunk.length / 4) : 0);
|
|
211
|
+
if (tokenCount + factTokens > options.tokenBudget) break;
|
|
212
|
+
tokenCount += factTokens;
|
|
213
|
+
budgetResults.push(r);
|
|
214
|
+
}
|
|
215
|
+
dedupedResults = budgetResults;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 6. Enrich with contradiction context
|
|
219
|
+
let results = await surfaceContradictions(config.storage, options.tenantId, dedupedResults);
|
|
220
|
+
console.error(`[steno-search] Fusion + dedup: ${Date.now() - t1}ms, Total: ${Date.now() - startTime}ms`);
|
|
221
|
+
|
|
222
|
+
// 6. Optionally enrich with graph context
|
|
223
|
+
if (options.includeGraph) {
|
|
224
|
+
for (const result of results) {
|
|
225
|
+
const entities = await config.storage.getEntitiesForFact(result.fact.id);
|
|
226
|
+
const edges: typeof result.graph extends undefined ? never : NonNullable<typeof result.graph>['edges'] = [];
|
|
227
|
+
for (const entity of entities) {
|
|
228
|
+
const entityEdges = await config.storage.getEdgesForEntity(options.tenantId, entity.id);
|
|
229
|
+
edges.push(...entityEdges);
|
|
230
|
+
}
|
|
231
|
+
result.graph = { entities, edges };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 7. Optionally enrich with fact history (previous versions)
|
|
236
|
+
if (options.includeHistory) {
|
|
237
|
+
for (const result of results) {
|
|
238
|
+
const history = await config.storage.getFactsByLineage(options.tenantId, result.fact.lineageId);
|
|
239
|
+
// Filter out the current fact, sort by version ascending
|
|
240
|
+
result.history = history
|
|
241
|
+
.filter(f => f.id !== result.fact.id)
|
|
242
|
+
.sort((a, b) => a.version - b.version);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 8. Record memory accesses for metamemory + update decay scores (fire-and-forget)
|
|
247
|
+
void recordAccesses(config.storage, options.tenantId, options.query, results, {
|
|
248
|
+
halfLifeDays: config.salienceHalfLifeDays,
|
|
249
|
+
normalizationK: config.salienceNormalizationK,
|
|
250
|
+
}).catch(err => console.error('[steno] Failed to record memory accesses:', err));
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
results,
|
|
254
|
+
triggersMatched,
|
|
255
|
+
totalCandidates: allCandidates.length,
|
|
256
|
+
durationMs: Date.now() - startTime,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Fast cosine similarity for pre-fusion reranking */
|
|
261
|
+
function cosineSim(a: number[], b: number[]): number {
|
|
262
|
+
if (a.length !== b.length || a.length === 0) return 0;
|
|
263
|
+
let dot = 0, normA = 0, normB = 0;
|
|
264
|
+
for (let i = 0; i < a.length; i++) {
|
|
265
|
+
dot += a[i]! * b[i]!;
|
|
266
|
+
normA += a[i]! * a[i]!;
|
|
267
|
+
normB += b[i]! * b[i]!;
|
|
268
|
+
}
|
|
269
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
270
|
+
return denom === 0 ? 0 : dot / denom;
|
|
271
|
+
}
|