@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.
Files changed (428) hide show
  1. package/dist/adapters/cache.d.ts +9 -0
  2. package/dist/adapters/cache.d.ts.map +1 -0
  3. package/dist/adapters/cache.js +2 -0
  4. package/dist/adapters/cache.js.map +1 -0
  5. package/dist/adapters/embedding.d.ts +7 -0
  6. package/dist/adapters/embedding.d.ts.map +1 -0
  7. package/dist/adapters/embedding.js +2 -0
  8. package/dist/adapters/embedding.js.map +1 -0
  9. package/dist/adapters/gemini-embedding.d.ts +18 -0
  10. package/dist/adapters/gemini-embedding.d.ts.map +1 -0
  11. package/dist/adapters/gemini-embedding.js +53 -0
  12. package/dist/adapters/gemini-embedding.js.map +1 -0
  13. package/dist/adapters/index.d.ts +7 -0
  14. package/dist/adapters/index.d.ts.map +1 -0
  15. package/dist/adapters/index.js +7 -0
  16. package/dist/adapters/index.js.map +1 -0
  17. package/dist/adapters/llm.d.ts +19 -0
  18. package/dist/adapters/llm.d.ts.map +1 -0
  19. package/dist/adapters/llm.js +2 -0
  20. package/dist/adapters/llm.js.map +1 -0
  21. package/dist/adapters/perplexity-embedding.d.ts +24 -0
  22. package/dist/adapters/perplexity-embedding.d.ts.map +1 -0
  23. package/dist/adapters/perplexity-embedding.js +78 -0
  24. package/dist/adapters/perplexity-embedding.js.map +1 -0
  25. package/dist/adapters/storage.d.ts +172 -0
  26. package/dist/adapters/storage.d.ts.map +1 -0
  27. package/dist/adapters/storage.js +2 -0
  28. package/dist/adapters/storage.js.map +1 -0
  29. package/dist/auth/api-key.d.ts +8 -0
  30. package/dist/auth/api-key.d.ts.map +1 -0
  31. package/dist/auth/api-key.js +27 -0
  32. package/dist/auth/api-key.js.map +1 -0
  33. package/dist/auth/index.d.ts +2 -0
  34. package/dist/auth/index.d.ts.map +1 -0
  35. package/dist/auth/index.js +2 -0
  36. package/dist/auth/index.js.map +1 -0
  37. package/dist/config.d.ts +296 -0
  38. package/dist/config.d.ts.map +1 -0
  39. package/dist/config.js +92 -0
  40. package/dist/config.js.map +1 -0
  41. package/dist/extraction/contradiction.d.ts +15 -0
  42. package/dist/extraction/contradiction.d.ts.map +1 -0
  43. package/dist/extraction/contradiction.js +23 -0
  44. package/dist/extraction/contradiction.js.map +1 -0
  45. package/dist/extraction/dedup.d.ts +12 -0
  46. package/dist/extraction/dedup.d.ts.map +1 -0
  47. package/dist/extraction/dedup.js +93 -0
  48. package/dist/extraction/dedup.js.map +1 -0
  49. package/dist/extraction/entity-extractor.d.ts +30 -0
  50. package/dist/extraction/entity-extractor.d.ts.map +1 -0
  51. package/dist/extraction/entity-extractor.js +145 -0
  52. package/dist/extraction/entity-extractor.js.map +1 -0
  53. package/dist/extraction/hasher.d.ts +5 -0
  54. package/dist/extraction/hasher.d.ts.map +1 -0
  55. package/dist/extraction/hasher.js +8 -0
  56. package/dist/extraction/hasher.js.map +1 -0
  57. package/dist/extraction/heuristic.d.ts +3 -0
  58. package/dist/extraction/heuristic.d.ts.map +1 -0
  59. package/dist/extraction/heuristic.js +282 -0
  60. package/dist/extraction/heuristic.js.map +1 -0
  61. package/dist/extraction/index.d.ts +10 -0
  62. package/dist/extraction/index.d.ts.map +1 -0
  63. package/dist/extraction/index.js +10 -0
  64. package/dist/extraction/index.js.map +1 -0
  65. package/dist/extraction/llm-extractor.d.ts +23 -0
  66. package/dist/extraction/llm-extractor.d.ts.map +1 -0
  67. package/dist/extraction/llm-extractor.js +238 -0
  68. package/dist/extraction/llm-extractor.js.map +1 -0
  69. package/dist/extraction/pipeline.d.ts +30 -0
  70. package/dist/extraction/pipeline.d.ts.map +1 -0
  71. package/dist/extraction/pipeline.js +398 -0
  72. package/dist/extraction/pipeline.js.map +1 -0
  73. package/dist/extraction/prompts.d.ts +28 -0
  74. package/dist/extraction/prompts.d.ts.map +1 -0
  75. package/dist/extraction/prompts.js +196 -0
  76. package/dist/extraction/prompts.js.map +1 -0
  77. package/dist/extraction/sliding-window.d.ts +41 -0
  78. package/dist/extraction/sliding-window.d.ts.map +1 -0
  79. package/dist/extraction/sliding-window.js +84 -0
  80. package/dist/extraction/sliding-window.js.map +1 -0
  81. package/dist/extraction/types.d.ts +80 -0
  82. package/dist/extraction/types.d.ts.map +1 -0
  83. package/dist/extraction/types.js +2 -0
  84. package/dist/extraction/types.js.map +1 -0
  85. package/dist/feedback/index.d.ts +2 -0
  86. package/dist/feedback/index.d.ts.map +1 -0
  87. package/dist/feedback/index.js +2 -0
  88. package/dist/feedback/index.js.map +1 -0
  89. package/dist/feedback/tracker.d.ts +25 -0
  90. package/dist/feedback/tracker.d.ts.map +1 -0
  91. package/dist/feedback/tracker.js +90 -0
  92. package/dist/feedback/tracker.js.map +1 -0
  93. package/dist/index.d.ts +12 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +13 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/models/api-key.d.ts +54 -0
  98. package/dist/models/api-key.d.ts.map +1 -0
  99. package/dist/models/api-key.js +21 -0
  100. package/dist/models/api-key.js.map +1 -0
  101. package/dist/models/edge.d.ts +78 -0
  102. package/dist/models/edge.d.ts.map +1 -0
  103. package/dist/models/edge.js +29 -0
  104. package/dist/models/edge.js.map +1 -0
  105. package/dist/models/entity.d.ts +60 -0
  106. package/dist/models/entity.d.ts.map +1 -0
  107. package/dist/models/entity.js +22 -0
  108. package/dist/models/entity.js.map +1 -0
  109. package/dist/models/extraction.d.ts +111 -0
  110. package/dist/models/extraction.d.ts.map +1 -0
  111. package/dist/models/extraction.js +40 -0
  112. package/dist/models/extraction.js.map +1 -0
  113. package/dist/models/fact-entity.d.ts +33 -0
  114. package/dist/models/fact-entity.d.ts.map +1 -0
  115. package/dist/models/fact-entity.js +14 -0
  116. package/dist/models/fact-entity.js.map +1 -0
  117. package/dist/models/fact.d.ts +191 -0
  118. package/dist/models/fact.d.ts.map +1 -0
  119. package/dist/models/fact.js +72 -0
  120. package/dist/models/fact.js.map +1 -0
  121. package/dist/models/index.d.ts +13 -0
  122. package/dist/models/index.d.ts.map +1 -0
  123. package/dist/models/index.js +13 -0
  124. package/dist/models/index.js.map +1 -0
  125. package/dist/models/memory-access.d.ts +89 -0
  126. package/dist/models/memory-access.d.ts.map +1 -0
  127. package/dist/models/memory-access.js +33 -0
  128. package/dist/models/memory-access.js.map +1 -0
  129. package/dist/models/session.d.ts +60 -0
  130. package/dist/models/session.d.ts.map +1 -0
  131. package/dist/models/session.js +23 -0
  132. package/dist/models/session.js.map +1 -0
  133. package/dist/models/tenant.d.ts +448 -0
  134. package/dist/models/tenant.d.ts.map +1 -0
  135. package/dist/models/tenant.js +23 -0
  136. package/dist/models/tenant.js.map +1 -0
  137. package/dist/models/trigger.d.ts +87 -0
  138. package/dist/models/trigger.d.ts.map +1 -0
  139. package/dist/models/trigger.js +41 -0
  140. package/dist/models/trigger.js.map +1 -0
  141. package/dist/models/usage-record.d.ts +37 -0
  142. package/dist/models/usage-record.d.ts.map +1 -0
  143. package/dist/models/usage-record.js +14 -0
  144. package/dist/models/usage-record.js.map +1 -0
  145. package/dist/models/webhook.d.ts +50 -0
  146. package/dist/models/webhook.d.ts.map +1 -0
  147. package/dist/models/webhook.js +25 -0
  148. package/dist/models/webhook.js.map +1 -0
  149. package/dist/profiles/index.d.ts +3 -0
  150. package/dist/profiles/index.d.ts.map +1 -0
  151. package/dist/profiles/index.js +2 -0
  152. package/dist/profiles/index.js.map +1 -0
  153. package/dist/profiles/profile.d.ts +22 -0
  154. package/dist/profiles/profile.d.ts.map +1 -0
  155. package/dist/profiles/profile.js +59 -0
  156. package/dist/profiles/profile.js.map +1 -0
  157. package/dist/retrieval/compound-search.d.ts +13 -0
  158. package/dist/retrieval/compound-search.d.ts.map +1 -0
  159. package/dist/retrieval/compound-search.js +87 -0
  160. package/dist/retrieval/compound-search.js.map +1 -0
  161. package/dist/retrieval/contradiction-surfacer.d.ts +18 -0
  162. package/dist/retrieval/contradiction-surfacer.d.ts.map +1 -0
  163. package/dist/retrieval/contradiction-surfacer.js +64 -0
  164. package/dist/retrieval/contradiction-surfacer.js.map +1 -0
  165. package/dist/retrieval/embedding-cache.d.ts +17 -0
  166. package/dist/retrieval/embedding-cache.d.ts.map +1 -0
  167. package/dist/retrieval/embedding-cache.js +56 -0
  168. package/dist/retrieval/embedding-cache.js.map +1 -0
  169. package/dist/retrieval/fusion.d.ts +27 -0
  170. package/dist/retrieval/fusion.d.ts.map +1 -0
  171. package/dist/retrieval/fusion.js +87 -0
  172. package/dist/retrieval/fusion.js.map +1 -0
  173. package/dist/retrieval/graph-traversal.d.ts +29 -0
  174. package/dist/retrieval/graph-traversal.d.ts.map +1 -0
  175. package/dist/retrieval/graph-traversal.js +208 -0
  176. package/dist/retrieval/graph-traversal.js.map +1 -0
  177. package/dist/retrieval/index.d.ts +14 -0
  178. package/dist/retrieval/index.d.ts.map +1 -0
  179. package/dist/retrieval/index.js +13 -0
  180. package/dist/retrieval/index.js.map +1 -0
  181. package/dist/retrieval/keyword-search.d.ts +4 -0
  182. package/dist/retrieval/keyword-search.d.ts.map +1 -0
  183. package/dist/retrieval/keyword-search.js +27 -0
  184. package/dist/retrieval/keyword-search.js.map +1 -0
  185. package/dist/retrieval/query-expansion.d.ts +20 -0
  186. package/dist/retrieval/query-expansion.d.ts.map +1 -0
  187. package/dist/retrieval/query-expansion.js +76 -0
  188. package/dist/retrieval/query-expansion.js.map +1 -0
  189. package/dist/retrieval/reranker.d.ts +15 -0
  190. package/dist/retrieval/reranker.d.ts.map +1 -0
  191. package/dist/retrieval/reranker.js +47 -0
  192. package/dist/retrieval/reranker.js.map +1 -0
  193. package/dist/retrieval/salience-scorer.d.ts +15 -0
  194. package/dist/retrieval/salience-scorer.d.ts.map +1 -0
  195. package/dist/retrieval/salience-scorer.js +41 -0
  196. package/dist/retrieval/salience-scorer.js.map +1 -0
  197. package/dist/retrieval/search.d.ts +21 -0
  198. package/dist/retrieval/search.d.ts.map +1 -0
  199. package/dist/retrieval/search.js +228 -0
  200. package/dist/retrieval/search.js.map +1 -0
  201. package/dist/retrieval/temporal-scorer.d.ts +18 -0
  202. package/dist/retrieval/temporal-scorer.d.ts.map +1 -0
  203. package/dist/retrieval/temporal-scorer.js +106 -0
  204. package/dist/retrieval/temporal-scorer.js.map +1 -0
  205. package/dist/retrieval/trigger-matcher.d.ts +18 -0
  206. package/dist/retrieval/trigger-matcher.d.ts.map +1 -0
  207. package/dist/retrieval/trigger-matcher.js +134 -0
  208. package/dist/retrieval/trigger-matcher.js.map +1 -0
  209. package/dist/retrieval/types.d.ts +70 -0
  210. package/dist/retrieval/types.d.ts.map +1 -0
  211. package/dist/retrieval/types.js +9 -0
  212. package/dist/retrieval/types.js.map +1 -0
  213. package/dist/retrieval/vector-search.d.ts +5 -0
  214. package/dist/retrieval/vector-search.d.ts.map +1 -0
  215. package/dist/retrieval/vector-search.js +24 -0
  216. package/dist/retrieval/vector-search.js.map +1 -0
  217. package/dist/salience/decay.d.ts +9 -0
  218. package/dist/salience/decay.d.ts.map +1 -0
  219. package/dist/salience/decay.js +15 -0
  220. package/dist/salience/decay.js.map +1 -0
  221. package/dist/salience/index.d.ts +2 -0
  222. package/dist/salience/index.d.ts.map +1 -0
  223. package/dist/salience/index.js +2 -0
  224. package/dist/salience/index.js.map +1 -0
  225. package/dist/scratchpad/index.d.ts +2 -0
  226. package/dist/scratchpad/index.d.ts.map +1 -0
  227. package/dist/scratchpad/index.js +2 -0
  228. package/dist/scratchpad/index.js.map +1 -0
  229. package/dist/scratchpad/scratchpad.d.ts +23 -0
  230. package/dist/scratchpad/scratchpad.d.ts.map +1 -0
  231. package/dist/scratchpad/scratchpad.js +107 -0
  232. package/dist/scratchpad/scratchpad.js.map +1 -0
  233. package/dist/sessions/index.d.ts +2 -0
  234. package/dist/sessions/index.d.ts.map +1 -0
  235. package/dist/sessions/index.js +2 -0
  236. package/dist/sessions/index.js.map +1 -0
  237. package/dist/sessions/manager.d.ts +11 -0
  238. package/dist/sessions/manager.d.ts.map +1 -0
  239. package/dist/sessions/manager.js +63 -0
  240. package/dist/sessions/manager.js.map +1 -0
  241. package/package.json +38 -0
  242. package/src/adapters/cache.d.ts +9 -0
  243. package/src/adapters/cache.d.ts.map +1 -0
  244. package/src/adapters/cache.js.map +1 -0
  245. package/src/adapters/cache.ts +8 -0
  246. package/src/adapters/embedding.d.ts +7 -0
  247. package/src/adapters/embedding.d.ts.map +1 -0
  248. package/src/adapters/embedding.js.map +1 -0
  249. package/src/adapters/embedding.ts +6 -0
  250. package/src/adapters/gemini-embedding.ts +67 -0
  251. package/src/adapters/index.ts +6 -0
  252. package/src/adapters/llm.d.ts +19 -0
  253. package/src/adapters/llm.d.ts.map +1 -0
  254. package/src/adapters/llm.js.map +1 -0
  255. package/src/adapters/llm.ts +16 -0
  256. package/src/adapters/perplexity-embedding.d.ts +24 -0
  257. package/src/adapters/perplexity-embedding.d.ts.map +1 -0
  258. package/src/adapters/perplexity-embedding.js.map +1 -0
  259. package/src/adapters/perplexity-embedding.ts +98 -0
  260. package/src/adapters/storage.d.ts +172 -0
  261. package/src/adapters/storage.d.ts.map +1 -0
  262. package/src/adapters/storage.js.map +1 -0
  263. package/src/adapters/storage.ts +187 -0
  264. package/src/auth/api-key.ts +33 -0
  265. package/src/auth/index.ts +1 -0
  266. package/src/config.d.ts +86 -0
  267. package/src/config.d.ts.map +1 -0
  268. package/src/config.js.map +1 -0
  269. package/src/config.ts +131 -0
  270. package/src/extraction/contradiction.d.ts +15 -0
  271. package/src/extraction/contradiction.d.ts.map +1 -0
  272. package/src/extraction/contradiction.js.map +1 -0
  273. package/src/extraction/contradiction.ts +33 -0
  274. package/src/extraction/dedup.d.ts +12 -0
  275. package/src/extraction/dedup.d.ts.map +1 -0
  276. package/src/extraction/dedup.js.map +1 -0
  277. package/src/extraction/dedup.ts +133 -0
  278. package/src/extraction/entity-extractor.d.ts +30 -0
  279. package/src/extraction/entity-extractor.d.ts.map +1 -0
  280. package/src/extraction/entity-extractor.js.map +1 -0
  281. package/src/extraction/entity-extractor.ts +193 -0
  282. package/src/extraction/hasher.d.ts +5 -0
  283. package/src/extraction/hasher.d.ts.map +1 -0
  284. package/src/extraction/hasher.js.map +1 -0
  285. package/src/extraction/hasher.ts +7 -0
  286. package/src/extraction/heuristic.d.ts +3 -0
  287. package/src/extraction/heuristic.d.ts.map +1 -0
  288. package/src/extraction/heuristic.js.map +1 -0
  289. package/src/extraction/heuristic.ts +341 -0
  290. package/src/extraction/index.ts +9 -0
  291. package/src/extraction/llm-extractor.d.ts +21 -0
  292. package/src/extraction/llm-extractor.d.ts.map +1 -0
  293. package/src/extraction/llm-extractor.js.map +1 -0
  294. package/src/extraction/llm-extractor.ts +267 -0
  295. package/src/extraction/pipeline.d.ts +27 -0
  296. package/src/extraction/pipeline.d.ts.map +1 -0
  297. package/src/extraction/pipeline.js.map +1 -0
  298. package/src/extraction/pipeline.ts +515 -0
  299. package/src/extraction/prompts.js.map +1 -0
  300. package/src/extraction/prompts.ts +233 -0
  301. package/src/extraction/sliding-window.d.ts +41 -0
  302. package/src/extraction/sliding-window.d.ts.map +1 -0
  303. package/src/extraction/sliding-window.js.map +1 -0
  304. package/src/extraction/sliding-window.ts +121 -0
  305. package/src/extraction/types.d.ts +68 -0
  306. package/src/extraction/types.d.ts.map +1 -0
  307. package/src/extraction/types.js.map +1 -0
  308. package/src/extraction/types.ts +80 -0
  309. package/src/feedback/index.ts +1 -0
  310. package/src/feedback/tracker.d.ts +25 -0
  311. package/src/feedback/tracker.d.ts.map +1 -0
  312. package/src/feedback/tracker.js.map +1 -0
  313. package/src/feedback/tracker.ts +119 -0
  314. package/src/index.ts +12 -0
  315. package/src/models/api-key.d.ts +54 -0
  316. package/src/models/api-key.d.ts.map +1 -0
  317. package/src/models/api-key.js.map +1 -0
  318. package/src/models/api-key.ts +26 -0
  319. package/src/models/edge.d.ts +78 -0
  320. package/src/models/edge.d.ts.map +1 -0
  321. package/src/models/edge.js.map +1 -0
  322. package/src/models/edge.ts +34 -0
  323. package/src/models/entity.d.ts +60 -0
  324. package/src/models/entity.d.ts.map +1 -0
  325. package/src/models/entity.js.map +1 -0
  326. package/src/models/entity.ts +27 -0
  327. package/src/models/extraction.d.ts +111 -0
  328. package/src/models/extraction.d.ts.map +1 -0
  329. package/src/models/extraction.js.map +1 -0
  330. package/src/models/extraction.ts +45 -0
  331. package/src/models/fact-entity.d.ts +33 -0
  332. package/src/models/fact-entity.d.ts.map +1 -0
  333. package/src/models/fact-entity.js.map +1 -0
  334. package/src/models/fact-entity.ts +19 -0
  335. package/src/models/fact.ts +85 -0
  336. package/src/models/index.d.ts +13 -0
  337. package/src/models/index.d.ts.map +1 -0
  338. package/src/models/index.js.map +1 -0
  339. package/src/models/index.ts +12 -0
  340. package/src/models/memory-access.d.ts +89 -0
  341. package/src/models/memory-access.d.ts.map +1 -0
  342. package/src/models/memory-access.js.map +1 -0
  343. package/src/models/memory-access.ts +41 -0
  344. package/src/models/session.d.ts +60 -0
  345. package/src/models/session.d.ts.map +1 -0
  346. package/src/models/session.js.map +1 -0
  347. package/src/models/session.ts +28 -0
  348. package/src/models/tenant.d.ts +214 -0
  349. package/src/models/tenant.d.ts.map +1 -0
  350. package/src/models/tenant.js.map +1 -0
  351. package/src/models/tenant.ts +28 -0
  352. package/src/models/trigger.d.ts +87 -0
  353. package/src/models/trigger.d.ts.map +1 -0
  354. package/src/models/trigger.js.map +1 -0
  355. package/src/models/trigger.ts +58 -0
  356. package/src/models/usage-record.d.ts +37 -0
  357. package/src/models/usage-record.d.ts.map +1 -0
  358. package/src/models/usage-record.js.map +1 -0
  359. package/src/models/usage-record.ts +16 -0
  360. package/src/models/webhook.d.ts +50 -0
  361. package/src/models/webhook.d.ts.map +1 -0
  362. package/src/models/webhook.js.map +1 -0
  363. package/src/models/webhook.ts +30 -0
  364. package/src/profiles/index.ts +2 -0
  365. package/src/profiles/profile.ts +81 -0
  366. package/src/retrieval/compound-search.d.ts +13 -0
  367. package/src/retrieval/compound-search.d.ts.map +1 -0
  368. package/src/retrieval/compound-search.js.map +1 -0
  369. package/src/retrieval/compound-search.ts +104 -0
  370. package/src/retrieval/contradiction-surfacer.d.ts +18 -0
  371. package/src/retrieval/contradiction-surfacer.d.ts.map +1 -0
  372. package/src/retrieval/contradiction-surfacer.js.map +1 -0
  373. package/src/retrieval/contradiction-surfacer.ts +87 -0
  374. package/src/retrieval/embedding-cache.d.ts +17 -0
  375. package/src/retrieval/embedding-cache.d.ts.map +1 -0
  376. package/src/retrieval/embedding-cache.js.map +1 -0
  377. package/src/retrieval/embedding-cache.ts +63 -0
  378. package/src/retrieval/fusion.d.ts +26 -0
  379. package/src/retrieval/fusion.d.ts.map +1 -0
  380. package/src/retrieval/fusion.js.map +1 -0
  381. package/src/retrieval/fusion.ts +129 -0
  382. package/src/retrieval/graph-traversal.d.ts +28 -0
  383. package/src/retrieval/graph-traversal.d.ts.map +1 -0
  384. package/src/retrieval/graph-traversal.js.map +1 -0
  385. package/src/retrieval/graph-traversal.ts +235 -0
  386. package/src/retrieval/index.ts +13 -0
  387. package/src/retrieval/keyword-search.ts +39 -0
  388. package/src/retrieval/query-expansion.d.ts +20 -0
  389. package/src/retrieval/query-expansion.d.ts.map +1 -0
  390. package/src/retrieval/query-expansion.js.map +1 -0
  391. package/src/retrieval/query-expansion.ts +86 -0
  392. package/src/retrieval/reranker.d.ts +15 -0
  393. package/src/retrieval/reranker.d.ts.map +1 -0
  394. package/src/retrieval/reranker.js.map +1 -0
  395. package/src/retrieval/reranker.ts +56 -0
  396. package/src/retrieval/salience-scorer.d.ts +15 -0
  397. package/src/retrieval/salience-scorer.d.ts.map +1 -0
  398. package/src/retrieval/salience-scorer.js.map +1 -0
  399. package/src/retrieval/salience-scorer.ts +57 -0
  400. package/src/retrieval/search.d.ts +21 -0
  401. package/src/retrieval/search.d.ts.map +1 -0
  402. package/src/retrieval/search.js.map +1 -0
  403. package/src/retrieval/search.ts +271 -0
  404. package/src/retrieval/temporal-scorer.ts +111 -0
  405. package/src/retrieval/trigger-matcher.d.ts +18 -0
  406. package/src/retrieval/trigger-matcher.d.ts.map +1 -0
  407. package/src/retrieval/trigger-matcher.js.map +1 -0
  408. package/src/retrieval/trigger-matcher.ts +180 -0
  409. package/src/retrieval/types.d.ts +66 -0
  410. package/src/retrieval/types.d.ts.map +1 -0
  411. package/src/retrieval/types.js.map +1 -0
  412. package/src/retrieval/types.ts +82 -0
  413. package/src/retrieval/vector-search.d.ts +5 -0
  414. package/src/retrieval/vector-search.d.ts.map +1 -0
  415. package/src/retrieval/vector-search.js.map +1 -0
  416. package/src/retrieval/vector-search.ts +38 -0
  417. package/src/salience/decay.d.ts +9 -0
  418. package/src/salience/decay.d.ts.map +1 -0
  419. package/src/salience/decay.js.map +1 -0
  420. package/src/salience/decay.ts +25 -0
  421. package/src/salience/index.ts +1 -0
  422. package/src/scratchpad/index.ts +1 -0
  423. package/src/scratchpad/scratchpad.d.ts +23 -0
  424. package/src/scratchpad/scratchpad.d.ts.map +1 -0
  425. package/src/scratchpad/scratchpad.js.map +1 -0
  426. package/src/scratchpad/scratchpad.ts +140 -0
  427. package/src/sessions/index.ts +1 -0
  428. 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
+ }