sensemaking 0.18.3 → 0.19.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 (368) hide show
  1. package/README.md +22 -4
  2. package/dist/cjs/chunk/group.js +10 -23
  3. package/dist/cjs/chunk/group.js.map +1 -1
  4. package/dist/cjs/chunk/parse.js +2 -5
  5. package/dist/cjs/chunk/parse.js.map +1 -1
  6. package/dist/cjs/cli/index.js.map +1 -1
  7. package/dist/cjs/cli/shared.js +6 -10
  8. package/dist/cjs/cli/shared.js.map +1 -1
  9. package/dist/cjs/cli/status.js +44 -10
  10. package/dist/cjs/cli/status.js.map +1 -1
  11. package/dist/cjs/cli.js +2 -8
  12. package/dist/cjs/cli.js.map +1 -1
  13. package/dist/cjs/commands/map.js +1 -3
  14. package/dist/cjs/commands/map.js.map +1 -1
  15. package/dist/cjs/commands/peek.js.map +1 -1
  16. package/dist/cjs/commands/related.js +3 -5
  17. package/dist/cjs/commands/related.js.map +1 -1
  18. package/dist/cjs/commands/scope.js.map +1 -1
  19. package/dist/cjs/commands/search.js +6 -8
  20. package/dist/cjs/commands/search.js.map +1 -1
  21. package/dist/cjs/commands/signals.js.map +1 -1
  22. package/dist/cjs/config/access.js.map +1 -1
  23. package/dist/cjs/config/index.d.cts +1 -1
  24. package/dist/cjs/config/index.d.ts +1 -1
  25. package/dist/cjs/config/index.js +3 -0
  26. package/dist/cjs/config/index.js.map +1 -1
  27. package/dist/cjs/config/load.js +10 -24
  28. package/dist/cjs/config/load.js.map +1 -1
  29. package/dist/cjs/config/resolve.js.map +1 -1
  30. package/dist/cjs/config/signals.js +2 -3
  31. package/dist/cjs/config/signals.js.map +1 -1
  32. package/dist/cjs/config/types.d.cts +2 -1
  33. package/dist/cjs/config/types.d.ts +2 -1
  34. package/dist/cjs/config/types.js +8 -0
  35. package/dist/cjs/config/types.js.map +1 -1
  36. package/dist/cjs/config/validate.d.cts +1 -1
  37. package/dist/cjs/config/validate.d.ts +1 -1
  38. package/dist/cjs/config/validate.js +9 -10
  39. package/dist/cjs/config/validate.js.map +1 -1
  40. package/dist/cjs/embed/cohere.js +2 -2
  41. package/dist/cjs/embed/cohere.js.map +1 -1
  42. package/dist/cjs/embed/distribution.js +3 -3
  43. package/dist/cjs/embed/distribution.js.map +1 -1
  44. package/dist/cjs/embed/handoff.d.cts +3 -0
  45. package/dist/cjs/embed/handoff.d.ts +3 -0
  46. package/dist/cjs/embed/handoff.js +39 -0
  47. package/dist/cjs/embed/handoff.js.map +1 -0
  48. package/dist/cjs/embed/identity.d.cts +11 -10
  49. package/dist/cjs/embed/identity.d.ts +11 -10
  50. package/dist/cjs/embed/identity.js +30 -15
  51. package/dist/cjs/embed/identity.js.map +1 -1
  52. package/dist/cjs/embed/langfit.js +2 -3
  53. package/dist/cjs/embed/langfit.js.map +1 -1
  54. package/dist/cjs/embed/languages.js +2 -4
  55. package/dist/cjs/embed/languages.js.map +1 -1
  56. package/dist/cjs/embed/openai.js +2 -2
  57. package/dist/cjs/embed/openai.js.map +1 -1
  58. package/dist/cjs/embed/query.js +58 -20
  59. package/dist/cjs/embed/query.js.map +1 -1
  60. package/dist/cjs/embed/registry.js +1 -2
  61. package/dist/cjs/embed/registry.js.map +1 -1
  62. package/dist/cjs/embed/static.d.cts +1 -1
  63. package/dist/cjs/embed/static.d.ts +1 -1
  64. package/dist/cjs/embed/static.js +8 -10
  65. package/dist/cjs/embed/static.js.map +1 -1
  66. package/dist/cjs/embed/store.d.cts +2 -2
  67. package/dist/cjs/embed/store.d.ts +2 -2
  68. package/dist/cjs/embed/store.js +48 -34
  69. package/dist/cjs/embed/store.js.map +1 -1
  70. package/dist/cjs/embed/types.js +1 -3
  71. package/dist/cjs/embed/types.js.map +1 -1
  72. package/dist/cjs/errors.d.cts +1 -1
  73. package/dist/cjs/errors.d.ts +1 -1
  74. package/dist/cjs/errors.js.map +1 -1
  75. package/dist/cjs/features/embed.js +19 -17
  76. package/dist/cjs/features/embed.js.map +1 -1
  77. package/dist/cjs/features/fences.js +5 -10
  78. package/dist/cjs/features/fences.js.map +1 -1
  79. package/dist/cjs/features/links.js +20 -37
  80. package/dist/cjs/features/links.js.map +1 -1
  81. package/dist/cjs/features/sections.js +21 -19
  82. package/dist/cjs/features/sections.js.map +1 -1
  83. package/dist/cjs/features/tags.js +5 -8
  84. package/dist/cjs/features/tags.js.map +1 -1
  85. package/dist/cjs/graph/traverse.js +1 -2
  86. package/dist/cjs/graph/traverse.js.map +1 -1
  87. package/dist/cjs/index.d.cts +1 -1
  88. package/dist/cjs/index.d.ts +1 -1
  89. package/dist/cjs/index.js +3 -0
  90. package/dist/cjs/index.js.map +1 -1
  91. package/dist/cjs/output/column-hint.js +3 -6
  92. package/dist/cjs/output/column-hint.js.map +1 -1
  93. package/dist/cjs/output/output.js +7 -14
  94. package/dist/cjs/output/output.js.map +1 -1
  95. package/dist/cjs/output/search-error.js +2 -5
  96. package/dist/cjs/output/search-error.js.map +1 -1
  97. package/dist/cjs/scan/frontmatter.d.cts +1 -0
  98. package/dist/cjs/scan/frontmatter.d.ts +1 -0
  99. package/dist/cjs/scan/frontmatter.js +14 -18
  100. package/dist/cjs/scan/frontmatter.js.map +1 -1
  101. package/dist/cjs/scan/list.js +2 -3
  102. package/dist/cjs/scan/list.js.map +1 -1
  103. package/dist/cjs/scan/reparse.js +12 -26
  104. package/dist/cjs/scan/reparse.js.map +1 -1
  105. package/dist/cjs/scan/worker-error.js.map +1 -1
  106. package/dist/cjs/store/cache.d.cts +2 -0
  107. package/dist/cjs/store/cache.d.ts +2 -0
  108. package/dist/cjs/store/cache.js +20 -0
  109. package/dist/cjs/store/cache.js.map +1 -0
  110. package/dist/cjs/store/duckdb/batch.js +4 -16
  111. package/dist/cjs/store/duckdb/batch.js.map +1 -1
  112. package/dist/cjs/store/duckdb/connection.js +8 -20
  113. package/dist/cjs/store/duckdb/connection.js.map +1 -1
  114. package/dist/cjs/store/duckdb/fieldStats.js +2 -8
  115. package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
  116. package/dist/cjs/store/duckdb/lexical.js +21 -29
  117. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  118. package/dist/cjs/store/duckdb/native.js.map +1 -1
  119. package/dist/cjs/store/duckdb/open.js +12 -13
  120. package/dist/cjs/store/duckdb/open.js.map +1 -1
  121. package/dist/cjs/store/duckdb/reconcile.js +4 -11
  122. package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
  123. package/dist/cjs/store/duckdb/sql-functions.js +2 -4
  124. package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
  125. package/dist/cjs/store/duckdb/store.js +2 -3
  126. package/dist/cjs/store/duckdb/store.js.map +1 -1
  127. package/dist/cjs/store/duckdb/vectors.js +8 -18
  128. package/dist/cjs/store/duckdb/vectors.js.map +1 -1
  129. package/dist/cjs/store/index.d.cts +3 -2
  130. package/dist/cjs/store/index.d.ts +3 -2
  131. package/dist/cjs/store/index.js +7 -8
  132. package/dist/cjs/store/index.js.map +1 -1
  133. package/dist/cjs/store/native.js +6 -16
  134. package/dist/cjs/store/native.js.map +1 -1
  135. package/dist/cjs/store/sql-functions.js.map +1 -1
  136. package/dist/cjs/store/sqlite/connection.js +4 -8
  137. package/dist/cjs/store/sqlite/connection.js.map +1 -1
  138. package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
  139. package/dist/cjs/store/sqlite/lexical.js +3 -5
  140. package/dist/cjs/store/sqlite/lexical.js.map +1 -1
  141. package/dist/cjs/store/sqlite/open.d.cts +0 -1
  142. package/dist/cjs/store/sqlite/open.d.ts +0 -1
  143. package/dist/cjs/store/sqlite/open.js +22 -40
  144. package/dist/cjs/store/sqlite/open.js.map +1 -1
  145. package/dist/cjs/store/sqlite/reconcile.js +2 -3
  146. package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
  147. package/dist/cjs/store/sqlite/sql-functions.js +2 -4
  148. package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
  149. package/dist/cjs/store/sqlite/store.js.map +1 -1
  150. package/dist/cjs/store/transaction.js +1 -3
  151. package/dist/cjs/store/transaction.js.map +1 -1
  152. package/dist/cjs/store/turso/connection.js +2 -6
  153. package/dist/cjs/store/turso/connection.js.map +1 -1
  154. package/dist/cjs/store/turso/fieldStats.js.map +1 -1
  155. package/dist/cjs/store/turso/lexical.d.cts +2 -0
  156. package/dist/cjs/store/turso/lexical.d.ts +2 -0
  157. package/dist/cjs/store/turso/lexical.js +347 -0
  158. package/dist/cjs/store/turso/lexical.js.map +1 -0
  159. package/dist/cjs/store/turso/native.js.map +1 -1
  160. package/dist/cjs/store/turso/open.d.cts +1 -1
  161. package/dist/cjs/store/turso/open.d.ts +1 -1
  162. package/dist/cjs/store/turso/open.js +81 -54
  163. package/dist/cjs/store/turso/open.js.map +1 -1
  164. package/dist/cjs/store/turso/reconcile.js +22 -22
  165. package/dist/cjs/store/turso/reconcile.js.map +1 -1
  166. package/dist/cjs/store/turso/store.js +18 -41
  167. package/dist/cjs/store/turso/store.js.map +1 -1
  168. package/dist/cjs/store/turso/vectors.d.cts +8 -0
  169. package/dist/cjs/store/turso/vectors.d.ts +8 -0
  170. package/dist/cjs/store/turso/vectors.js +435 -0
  171. package/dist/cjs/store/turso/vectors.js.map +1 -0
  172. package/dist/cjs/store/types.js +2 -3
  173. package/dist/cjs/store/types.js.map +1 -1
  174. package/dist/cjs/store/vectors.js.map +1 -1
  175. package/dist/cjs/text/segment.d.cts +1 -0
  176. package/dist/cjs/text/segment.d.ts +1 -0
  177. package/dist/cjs/text/segment.js +10 -14
  178. package/dist/cjs/text/segment.js.map +1 -1
  179. package/dist/cjs/watch.js +2 -5
  180. package/dist/cjs/watch.js.map +1 -1
  181. package/dist/cjs/workers/parse.js.map +1 -1
  182. package/dist/esm/chunk/group.js +10 -23
  183. package/dist/esm/chunk/group.js.map +1 -1
  184. package/dist/esm/chunk/parse.js +4 -8
  185. package/dist/esm/chunk/parse.js.map +1 -1
  186. package/dist/esm/cli/index.js +3 -5
  187. package/dist/esm/cli/index.js.map +1 -1
  188. package/dist/esm/cli/shared.js +12 -22
  189. package/dist/esm/cli/shared.js.map +1 -1
  190. package/dist/esm/cli/status.js +43 -9
  191. package/dist/esm/cli/status.js.map +1 -1
  192. package/dist/esm/cli.js +2 -8
  193. package/dist/esm/cli.js.map +1 -1
  194. package/dist/esm/commands/map.js +1 -3
  195. package/dist/esm/commands/map.js.map +1 -1
  196. package/dist/esm/commands/peek.js.map +1 -1
  197. package/dist/esm/commands/related.js +3 -5
  198. package/dist/esm/commands/related.js.map +1 -1
  199. package/dist/esm/commands/scope.js +3 -5
  200. package/dist/esm/commands/scope.js.map +1 -1
  201. package/dist/esm/commands/search.js +10 -16
  202. package/dist/esm/commands/search.js.map +1 -1
  203. package/dist/esm/commands/signals.js +3 -7
  204. package/dist/esm/commands/signals.js.map +1 -1
  205. package/dist/esm/config/access.js +8 -13
  206. package/dist/esm/config/access.js.map +1 -1
  207. package/dist/esm/config/index.d.ts +1 -1
  208. package/dist/esm/config/index.js +1 -1
  209. package/dist/esm/config/index.js.map +1 -1
  210. package/dist/esm/config/load.js +10 -24
  211. package/dist/esm/config/load.js.map +1 -1
  212. package/dist/esm/config/resolve.js +2 -3
  213. package/dist/esm/config/resolve.js.map +1 -1
  214. package/dist/esm/config/signals.js +3 -5
  215. package/dist/esm/config/signals.js.map +1 -1
  216. package/dist/esm/config/types.d.ts +2 -1
  217. package/dist/esm/config/types.js +8 -2
  218. package/dist/esm/config/types.js.map +1 -1
  219. package/dist/esm/config/validate.d.ts +1 -1
  220. package/dist/esm/config/validate.js +7 -10
  221. package/dist/esm/config/validate.js.map +1 -1
  222. package/dist/esm/embed/cohere.js +2 -2
  223. package/dist/esm/embed/cohere.js.map +1 -1
  224. package/dist/esm/embed/distribution.js +1 -1
  225. package/dist/esm/embed/distribution.js.map +1 -1
  226. package/dist/esm/embed/handoff.d.ts +3 -0
  227. package/dist/esm/embed/handoff.js +21 -0
  228. package/dist/esm/embed/handoff.js.map +1 -0
  229. package/dist/esm/embed/identity.d.ts +11 -10
  230. package/dist/esm/embed/identity.js +29 -26
  231. package/dist/esm/embed/identity.js.map +1 -1
  232. package/dist/esm/embed/langfit.js +2 -3
  233. package/dist/esm/embed/langfit.js.map +1 -1
  234. package/dist/esm/embed/languages.js +2 -4
  235. package/dist/esm/embed/languages.js.map +1 -1
  236. package/dist/esm/embed/openai.js +2 -2
  237. package/dist/esm/embed/openai.js.map +1 -1
  238. package/dist/esm/embed/query.js +21 -6
  239. package/dist/esm/embed/query.js.map +1 -1
  240. package/dist/esm/embed/registry.js +1 -2
  241. package/dist/esm/embed/registry.js.map +1 -1
  242. package/dist/esm/embed/static.d.ts +1 -1
  243. package/dist/esm/embed/static.js +8 -10
  244. package/dist/esm/embed/static.js.map +1 -1
  245. package/dist/esm/embed/store.d.ts +2 -2
  246. package/dist/esm/embed/store.js +28 -23
  247. package/dist/esm/embed/store.js.map +1 -1
  248. package/dist/esm/embed/types.js +1 -3
  249. package/dist/esm/embed/types.js.map +1 -1
  250. package/dist/esm/errors.d.ts +1 -1
  251. package/dist/esm/errors.js.map +1 -1
  252. package/dist/esm/features/embed.js +16 -16
  253. package/dist/esm/features/embed.js.map +1 -1
  254. package/dist/esm/features/fences.js +9 -19
  255. package/dist/esm/features/fences.js.map +1 -1
  256. package/dist/esm/features/links.js +24 -49
  257. package/dist/esm/features/links.js.map +1 -1
  258. package/dist/esm/features/sections.js +20 -20
  259. package/dist/esm/features/sections.js.map +1 -1
  260. package/dist/esm/features/tags.js +5 -8
  261. package/dist/esm/features/tags.js.map +1 -1
  262. package/dist/esm/features/types.js.map +1 -1
  263. package/dist/esm/graph/traverse.js +1 -2
  264. package/dist/esm/graph/traverse.js.map +1 -1
  265. package/dist/esm/index.d.ts +1 -1
  266. package/dist/esm/index.js +1 -1
  267. package/dist/esm/index.js.map +1 -1
  268. package/dist/esm/output/column-hint.js +3 -6
  269. package/dist/esm/output/column-hint.js.map +1 -1
  270. package/dist/esm/output/output.js +9 -20
  271. package/dist/esm/output/output.js.map +1 -1
  272. package/dist/esm/output/search-error.js +2 -5
  273. package/dist/esm/output/search-error.js.map +1 -1
  274. package/dist/esm/scan/frontmatter.d.ts +1 -0
  275. package/dist/esm/scan/frontmatter.js +13 -18
  276. package/dist/esm/scan/frontmatter.js.map +1 -1
  277. package/dist/esm/scan/list.js +2 -3
  278. package/dist/esm/scan/list.js.map +1 -1
  279. package/dist/esm/scan/reparse.js +16 -34
  280. package/dist/esm/scan/reparse.js.map +1 -1
  281. package/dist/esm/scan/worker-error.js.map +1 -1
  282. package/dist/esm/store/cache.d.ts +2 -0
  283. package/dist/esm/store/cache.js +11 -0
  284. package/dist/esm/store/cache.js.map +1 -0
  285. package/dist/esm/store/duckdb/batch.js +4 -16
  286. package/dist/esm/store/duckdb/batch.js.map +1 -1
  287. package/dist/esm/store/duckdb/connection.js +8 -20
  288. package/dist/esm/store/duckdb/connection.js.map +1 -1
  289. package/dist/esm/store/duckdb/fieldStats.js +4 -12
  290. package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
  291. package/dist/esm/store/duckdb/lexical.js +29 -36
  292. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  293. package/dist/esm/store/duckdb/native.js +2 -7
  294. package/dist/esm/store/duckdb/native.js.map +1 -1
  295. package/dist/esm/store/duckdb/open.js +16 -23
  296. package/dist/esm/store/duckdb/open.js.map +1 -1
  297. package/dist/esm/store/duckdb/reconcile.js +4 -11
  298. package/dist/esm/store/duckdb/reconcile.js.map +1 -1
  299. package/dist/esm/store/duckdb/sql-functions.js +4 -9
  300. package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
  301. package/dist/esm/store/duckdb/store.js +6 -14
  302. package/dist/esm/store/duckdb/store.js.map +1 -1
  303. package/dist/esm/store/duckdb/vectors.js +14 -31
  304. package/dist/esm/store/duckdb/vectors.js.map +1 -1
  305. package/dist/esm/store/index.d.ts +3 -2
  306. package/dist/esm/store/index.js +5 -6
  307. package/dist/esm/store/index.js.map +1 -1
  308. package/dist/esm/store/native.js +10 -25
  309. package/dist/esm/store/native.js.map +1 -1
  310. package/dist/esm/store/sql-functions.js +3 -5
  311. package/dist/esm/store/sql-functions.js.map +1 -1
  312. package/dist/esm/store/sqlite/connection.js +4 -8
  313. package/dist/esm/store/sqlite/connection.js.map +1 -1
  314. package/dist/esm/store/sqlite/fieldStats.js +2 -6
  315. package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
  316. package/dist/esm/store/sqlite/lexical.js +5 -9
  317. package/dist/esm/store/sqlite/lexical.js.map +1 -1
  318. package/dist/esm/store/sqlite/open.d.ts +0 -1
  319. package/dist/esm/store/sqlite/open.js +21 -41
  320. package/dist/esm/store/sqlite/open.js.map +1 -1
  321. package/dist/esm/store/sqlite/reconcile.js +6 -13
  322. package/dist/esm/store/sqlite/reconcile.js.map +1 -1
  323. package/dist/esm/store/sqlite/sql-functions.js +2 -4
  324. package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
  325. package/dist/esm/store/sqlite/store.js +1 -2
  326. package/dist/esm/store/sqlite/store.js.map +1 -1
  327. package/dist/esm/store/transaction.js +2 -5
  328. package/dist/esm/store/transaction.js.map +1 -1
  329. package/dist/esm/store/turso/connection.js +2 -6
  330. package/dist/esm/store/turso/connection.js.map +1 -1
  331. package/dist/esm/store/turso/fieldStats.js +2 -5
  332. package/dist/esm/store/turso/fieldStats.js.map +1 -1
  333. package/dist/esm/store/turso/lexical.d.ts +2 -0
  334. package/dist/esm/store/turso/lexical.js +128 -0
  335. package/dist/esm/store/turso/lexical.js.map +1 -0
  336. package/dist/esm/store/turso/native.js +2 -7
  337. package/dist/esm/store/turso/native.js.map +1 -1
  338. package/dist/esm/store/turso/open.d.ts +1 -1
  339. package/dist/esm/store/turso/open.js +36 -29
  340. package/dist/esm/store/turso/open.js.map +1 -1
  341. package/dist/esm/store/turso/reconcile.js +22 -22
  342. package/dist/esm/store/turso/reconcile.js.map +1 -1
  343. package/dist/esm/store/turso/store.js +17 -28
  344. package/dist/esm/store/turso/store.js.map +1 -1
  345. package/dist/esm/store/turso/vectors.d.ts +8 -0
  346. package/dist/esm/store/turso/vectors.js +98 -0
  347. package/dist/esm/store/turso/vectors.js.map +1 -0
  348. package/dist/esm/store/types.js +2 -3
  349. package/dist/esm/store/types.js.map +1 -1
  350. package/dist/esm/store/vectors.js +2 -3
  351. package/dist/esm/store/vectors.js.map +1 -1
  352. package/dist/esm/text/segment.d.ts +1 -0
  353. package/dist/esm/text/segment.js +13 -21
  354. package/dist/esm/text/segment.js.map +1 -1
  355. package/dist/esm/watch.js +2 -5
  356. package/dist/esm/watch.js.map +1 -1
  357. package/dist/esm/workers/parse.js.map +1 -1
  358. package/package.json +3 -1
  359. package/schema.json +2 -2
  360. package/skills/sense/SKILL.md +2 -2
  361. package/skills/sense-setup/SKILL.md +3 -3
  362. package/dist/cjs/store/meta.d.cts +0 -3
  363. package/dist/cjs/store/meta.d.ts +0 -3
  364. package/dist/cjs/store/meta.js +0 -215
  365. package/dist/cjs/store/meta.js.map +0 -1
  366. package/dist/esm/store/meta.d.ts +0 -3
  367. package/dist/esm/store/meta.js +0 -17
  368. package/dist/esm/store/meta.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/openai.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { fetchWithRetry } from './http.ts';\nimport type { EmbedProvider } from './types.ts';\n\nconst BATCH_CAP = 64;\n\n// One POST against any OpenAI-compatible /embeddings endpoint: Ollama, LM Studio, Cloudflare\n// Workers AI, Jina, Voyage, and Gemini's compat base URL all serve this shape.\nexport async function openaiProvider(model: string, url: string | undefined, keyEnv: string | undefined): Promise<EmbedProvider> {\n if (!url) throw new SenseError('EMBED_MODEL', 'embed.provider \"openai\" requires a url');\n const base = url.replace(/\\/+$/, '');\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n const key = keyEnv ? process.env[keyEnv] : undefined;\n if (key) headers.authorization = `Bearer ${key}`;\n\n async function post(texts: string[]): Promise<Float32Array[]> {\n const res = await fetchWithRetry(`${base}/embeddings`, { method: 'POST', headers, body: JSON.stringify({ model, input: texts }) });\n if (!res.ok) throw new SenseError('EMBED_MODEL', `${base}/embeddings -> HTTP ${res.status}`);\n const body = (await res.json()) as { data: Array<{ embedding: number[]; index?: number }> };\n // The schema carries `index` because response order is not promised, and the caller maps\n // vectors back to chunks positionally: sort by it whenever every element has one.\n const data = body.data.every((d) => typeof d.index === 'number') ? [...body.data].sort((a, b) => (a.index as number) - (b.index as number)) : body.data;\n // A server that drops an input (empty or over-length strings are the usual cause) would\n // otherwise shift every later vector onto the wrong chunk, silently.\n if (data.length !== texts.length) throw new SenseError('EMBED_MODEL', `${base}/embeddings returned ${data.length} embeddings for ${texts.length} inputs`);\n return data.map((d) => Float32Array.from(d.embedding));\n }\n\n const dims = (await post(['dimension probe']))[0].length;\n // Symmetric for now: per-model prefixes (nomic's search_document/search_query) are a\n // later workstream.\n return { id: `openai:${base}:${model}`, dims, batchCap: BATCH_CAP, embedDocuments: post, embedQuery: async (text) => (await post([text]))[0] };\n}\n"],"names":["openaiProvider","BATCH_CAP","model","url","keyEnv","base","headers","key","dims","post","texts","res","body","data","fetchWithRetry","method","JSON","stringify","input","ok","SenseError","status","json","every","d","index","sort","a","b","length","map","Float32Array","from","embedding","replace","process","env","undefined","authorization","id","batchCap","embedDocuments","embedQuery","text"],"mappings":";;;;+BAQsBA;;;eAAAA;;;wBARK;sBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG/B,IAAMC,YAAY;AAIX,SAAeD,eAAeE,KAAa,EAAEC,GAAuB,EAAEC,MAA0B;;YAE/FC,MACAC,SACAC,KAgBAC;QAbN,SAAeC,KAAKC,KAAe;;oBAC3BC,KAEAC,MAGAC;;;;4BALM;;gCAAMC,IAAAA,sBAAc,EAAC,AAAC,GAAO,OAALT,MAAK,gBAAc;oCAAEU,QAAQ;oCAAQT,SAAAA;oCAASM,MAAMI,KAAKC,SAAS,CAAC;wCAAEf,OAAAA;wCAAOgB,OAAOR;oCAAM;gCAAG;;;4BAA1HC,MAAM;4BACZ,IAAI,CAACA,IAAIQ,EAAE,EAAE,MAAM,IAAIC,oBAAU,CAAC,eAAe,AAAC,GAA6BT,OAA3BN,MAAK,wBAAiC,OAAXM,IAAIU,MAAM;4BAC3E;;gCAAMV,IAAIW,IAAI;;;4BAAtBV,OAAQ;4BACd,yFAAyF;4BACzF,kFAAkF;4BAC5EC,OAAOD,KAAKC,IAAI,CAACU,KAAK,CAAC,SAACC;uCAAM,OAAOA,EAAEC,KAAK,KAAK;iCAAY,AAAC,qBAAGb,KAAKC,IAAI,EAAEa,IAAI,CAAC,SAACC,GAAGC;uCAAM,AAACD,EAAEF,KAAK,GAAeG,EAAEH,KAAK;iCAAeb,KAAKC,IAAI;4BACvJ,wFAAwF;4BACxF,qEAAqE;4BACrE,IAAIA,KAAKgB,MAAM,KAAKnB,MAAMmB,MAAM,EAAE,MAAM,IAAIT,oBAAU,CAAC,eAAe,AAAC,GAA8BP,OAA5BR,MAAK,yBAAqDK,OAA9BG,KAAKgB,MAAM,EAAC,oBAA+B,OAAbnB,MAAMmB,MAAM,EAAC;4BAChJ;;gCAAOhB,KAAKiB,GAAG,CAAC,SAACN;2CAAMO,aAAaC,IAAI,CAACR,EAAES,SAAS;;;;;YACtD;;;;;oBAjBA,IAAI,CAAC9B,KAAK,MAAM,IAAIiB,oBAAU,CAAC,eAAe;oBACxCf,OAAOF,IAAI+B,OAAO,CAAC,QAAQ;oBAC3B5B,UAAkC;wBAAE,gBAAgB;oBAAmB;oBACvEC,MAAMH,SAAS+B,QAAQC,GAAG,CAAChC,OAAO,GAAGiC;oBAC3C,IAAI9B,KAAKD,QAAQgC,aAAa,GAAG,AAAC,UAAa,OAAJ/B;oBAe7B;;wBAAME;4BAAM;;;;oBAApBD,OAAO,AAAC,aAAgC,CAAC,EAAE,CAACqB,MAAM;oBACxD,qFAAqF;oBACrF,oBAAoB;oBACpB;;wBAAO;4BAAEU,IAAI,AAAC,UAAiBrC,OAARG,MAAK,KAAS,OAANH;4BAASM,MAAAA;4BAAMgC,UAAUvC;4BAAWwC,gBAAgBhC;4BAAMiC,YAAY,SAAZA,WAAmBC;;;;;gDAAU;;oDAAMlC;wDAAMkC;;;;;;oDAAZ,aAAmB,CAAC,EAAE;;;;;;wBAAC;;;;IAC/I"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/openai.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { fetchWithRetry } from './http.ts';\nimport type { EmbedProvider } from './types.ts';\n\nconst BATCH_CAP = 64;\n\n// One POST against any OpenAI-compatible /embeddings endpoint: Ollama, LM Studio, Cloudflare\n// Workers AI, Jina, Voyage, and Gemini's compat base URL all serve this shape.\nexport async function openaiProvider(model: string, url: string | undefined, keyEnv: string | undefined): Promise<EmbedProvider> {\n if (!url) throw new SenseError('EMBED_MODEL', 'embed.provider \"openai\" requires a url');\n const base = url.replace(/\\/+$/, '');\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n const key = keyEnv ? process.env[keyEnv] : undefined;\n if (key) headers.authorization = `Bearer ${key}`;\n\n async function post(texts: string[]): Promise<Float32Array[]> {\n const res = await fetchWithRetry(`${base}/embeddings`, { method: 'POST', headers, body: JSON.stringify({ model, input: texts }) });\n if (!res.ok) throw new SenseError('EMBED_MODEL', `${base}/embeddings -> HTTP ${res.status}`);\n const body = (await res.json()) as { data: Array<{ embedding: number[]; index?: number }> };\n // The schema carries `index` because response order is not promised, and the caller maps\n // vectors back to chunks positionally: sort by it whenever every element has one.\n const data = body.data.every((d) => typeof d.index === 'number') ? [...body.data].sort((a, b) => (a.index as number) - (b.index as number)) : body.data;\n // A server that drops an input (empty or over-length strings are the usual cause) would\n // otherwise shift every later vector onto the wrong chunk, silently.\n if (data.length !== texts.length) throw new SenseError('EMBED_MODEL', `${base}/embeddings returned ${data.length} embeddings for ${texts.length} inputs`);\n return data.map((d) => Float32Array.from(d.embedding));\n }\n\n const dims = (await post(['dimension probe']))[0].length;\n // embedQuery and embedDocuments are symmetric here; per-model prefixes like nomic's\n // search_document/search_query are not applied.\n return { id: `openai:${base}:${model}`, dims, batchCap: BATCH_CAP, embedDocuments: post, embedQuery: async (text) => (await post([text]))[0] };\n}\n"],"names":["openaiProvider","BATCH_CAP","model","url","keyEnv","base","headers","key","dims","post","texts","res","body","data","fetchWithRetry","method","JSON","stringify","input","ok","SenseError","status","json","every","d","index","sort","a","b","length","map","Float32Array","from","embedding","replace","process","env","undefined","authorization","id","batchCap","embedDocuments","embedQuery","text"],"mappings":";;;;+BAQsBA;;;eAAAA;;;wBARK;sBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG/B,IAAMC,YAAY;AAIX,SAAeD,eAAeE,KAAa,EAAEC,GAAuB,EAAEC,MAA0B;;YAE/FC,MACAC,SACAC,KAgBAC;QAbN,SAAeC,KAAKC,KAAe;;oBAC3BC,KAEAC,MAGAC;;;;4BALM;;gCAAMC,IAAAA,sBAAc,EAAC,AAAC,GAAO,OAALT,MAAK,gBAAc;oCAAEU,QAAQ;oCAAQT,SAAAA;oCAASM,MAAMI,KAAKC,SAAS,CAAC;wCAAEf,OAAAA;wCAAOgB,OAAOR;oCAAM;gCAAG;;;4BAA1HC,MAAM;4BACZ,IAAI,CAACA,IAAIQ,EAAE,EAAE,MAAM,IAAIC,oBAAU,CAAC,eAAe,AAAC,GAA6BT,OAA3BN,MAAK,wBAAiC,OAAXM,IAAIU,MAAM;4BAC3E;;gCAAMV,IAAIW,IAAI;;;4BAAtBV,OAAQ;4BACd,yFAAyF;4BACzF,kFAAkF;4BAC5EC,OAAOD,KAAKC,IAAI,CAACU,KAAK,CAAC,SAACC;uCAAM,OAAOA,EAAEC,KAAK,KAAK;iCAAY,AAAC,qBAAGb,KAAKC,IAAI,EAAEa,IAAI,CAAC,SAACC,GAAGC;uCAAM,AAACD,EAAEF,KAAK,GAAeG,EAAEH,KAAK;iCAAeb,KAAKC,IAAI;4BACvJ,wFAAwF;4BACxF,qEAAqE;4BACrE,IAAIA,KAAKgB,MAAM,KAAKnB,MAAMmB,MAAM,EAAE,MAAM,IAAIT,oBAAU,CAAC,eAAe,AAAC,GAA8BP,OAA5BR,MAAK,yBAAqDK,OAA9BG,KAAKgB,MAAM,EAAC,oBAA+B,OAAbnB,MAAMmB,MAAM,EAAC;4BAChJ;;gCAAOhB,KAAKiB,GAAG,CAAC,SAACN;2CAAMO,aAAaC,IAAI,CAACR,EAAES,SAAS;;;;;YACtD;;;;;oBAjBA,IAAI,CAAC9B,KAAK,MAAM,IAAIiB,oBAAU,CAAC,eAAe;oBACxCf,OAAOF,IAAI+B,OAAO,CAAC,QAAQ;oBAC3B5B,UAAkC;wBAAE,gBAAgB;oBAAmB;oBACvEC,MAAMH,SAAS+B,QAAQC,GAAG,CAAChC,OAAO,GAAGiC;oBAC3C,IAAI9B,KAAKD,QAAQgC,aAAa,GAAG,AAAC,UAAa,OAAJ/B;oBAe7B;;wBAAME;4BAAM;;;;oBAApBD,OAAO,AAAC,aAAgC,CAAC,EAAE,CAACqB,MAAM;oBACxD,oFAAoF;oBACpF,gDAAgD;oBAChD;;wBAAO;4BAAEU,IAAI,AAAC,UAAiBrC,OAARG,MAAK,KAAS,OAANH;4BAASM,MAAAA;4BAAMgC,UAAUvC;4BAAWwC,gBAAgBhC;4BAAMiC,YAAY,SAAZA,WAAmBC;;;;;gDAAU;;oDAAMlC;wDAAMkC;;;;;;oDAAZ,aAAmB,CAAC,EAAE;;;;;;wBAAC;;;;IAC/I"}
@@ -25,11 +25,13 @@ _export(exports, {
25
25
  return toStore;
26
26
  }
27
27
  });
28
+ var _nodefs = require("node:fs");
28
29
  var _nodepath = require("node:path");
29
30
  var _errorsts = require("../errors.js");
30
31
  var _embedts = require("../features/embed.js");
31
32
  var _progressts = require("../output/progress.js");
32
33
  var _indexts = require("../scan/index.js");
34
+ var _handoffts = require("./handoff.js");
33
35
  var _langfitts = require("./langfit.js");
34
36
  var _registryts = require("./registry.js");
35
37
  var _typests = require("./types.js");
@@ -243,7 +245,7 @@ function toStore(full, dims, int8) {
243
245
  }
244
246
  function embedPending(store, cfg, baseDir) {
245
247
  return _async_to_generator(function() {
246
- var _loop, provider, dirty, storeDims, byPath, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, row, _byPath_get, list, jobs, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, path, chunkIdxs, chunks, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, idx, report, i;
248
+ var _loop, _takeChunkText, provider, dirty, storeDims, byPath, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, row, _byPath_get, list, textByPath, jobs, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _loop1, _iterator1, _step1, report, i;
247
249
  return _ts_generator(this, function(_state) {
248
250
  switch(_state.label){
249
251
  case 0:
@@ -324,15 +326,49 @@ function embedPending(store, cfg, baseDir) {
324
326
  }
325
327
  }
326
328
  }
329
+ textByPath = (_takeChunkText = (0, _handoffts.takeChunkText)(store)) !== null && _takeChunkText !== void 0 ? _takeChunkText : new Map();
327
330
  jobs = [];
328
331
  _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
329
332
  try {
330
- for(_iterator1 = byPath[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
331
- _step_value = _sliced_to_array(_step1.value, 2), path = _step_value[0], chunkIdxs = _step_value[1];
332
- chunks = void 0;
333
+ _loop1 = function() {
334
+ var _step_value = _sliced_to_array(_step1.value, 2), path = _step_value[0], chunkIdxs = _step_value[1];
335
+ var texts = textByPath.get(path);
336
+ if (texts && chunkIdxs.every(function(idx) {
337
+ return idx < texts.length;
338
+ })) {
339
+ // A stat, not a parse: a file that vanished since reconcile is skipped here even though its
340
+ // text comes from memory, and the next reconcile removes its rows.
341
+ if (!(0, _nodefs.existsSync)((0, _nodepath.join)(baseDir, path))) return "continue";
342
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
343
+ try {
344
+ for(var _iterator = chunkIdxs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
345
+ var idx = _step.value;
346
+ jobs.push({
347
+ path: path,
348
+ chunk: idx,
349
+ text: texts[idx]
350
+ });
351
+ }
352
+ } catch (err) {
353
+ _didIteratorError = true;
354
+ _iteratorError = err;
355
+ } finally{
356
+ try {
357
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
358
+ _iterator.return();
359
+ }
360
+ } finally{
361
+ if (_didIteratorError) {
362
+ throw _iteratorError;
363
+ }
364
+ }
365
+ }
366
+ return "continue";
367
+ }
368
+ // Reconcile ran in another process (`sense map` earlier, or a background `sense watch`), so
369
+ // its chunk text is gone: re-derive this one file.
370
+ var chunks = void 0;
333
371
  try {
334
- // presets/embed are irrelevant here -- re-deriving chunk text for a doc that already
335
- // has embeddings rows means the tree had an embedding model at reconcile time.
336
372
  chunks = (0, _indexts.parseFile)({
337
373
  relPath: path,
338
374
  absPath: (0, _nodepath.join)(baseDir, path),
@@ -345,33 +381,35 @@ function embedPending(store, cfg, baseDir) {
345
381
  _embedts.embed
346
382
  ], cfg).doc.extracted.embed;
347
383
  } catch (unused) {
348
- continue; // vanished since reconcile; the next reconcile removes its rows
384
+ return "continue" // vanished since reconcile; the next reconcile removes its rows
385
+ ;
349
386
  }
350
- _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
387
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
351
388
  try {
352
- for(_iterator2 = chunkIdxs[Symbol.iterator](); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
353
- idx = _step2.value;
354
- if (chunks[idx]) jobs.push({
389
+ for(var _iterator1 = chunkIdxs[Symbol.iterator](), _step2; !(_iteratorNormalCompletion1 = (_step2 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
390
+ var idx1 = _step2.value;
391
+ if (chunks[idx1]) jobs.push({
355
392
  path: path,
356
- chunk: idx,
357
- text: chunks[idx].text
393
+ chunk: idx1,
394
+ text: chunks[idx1].text
358
395
  });
359
396
  }
360
397
  } catch (err) {
361
- _didIteratorError2 = true;
362
- _iteratorError2 = err;
398
+ _didIteratorError1 = true;
399
+ _iteratorError1 = err;
363
400
  } finally{
364
401
  try {
365
- if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
366
- _iterator2.return();
402
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
403
+ _iterator1.return();
367
404
  }
368
405
  } finally{
369
- if (_didIteratorError2) {
370
- throw _iteratorError2;
406
+ if (_didIteratorError1) {
407
+ throw _iteratorError1;
371
408
  }
372
409
  }
373
410
  }
374
- }
411
+ };
412
+ for(_iterator1 = byPath[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true)_loop1();
375
413
  } catch (err) {
376
414
  _didIteratorError1 = true;
377
415
  _iteratorError1 = err;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/query.ts"],"sourcesContent":["import { join } from 'node:path';\nimport type { Config, ResolvedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport type { Chunk } from '../features/embed.ts';\nimport { embed } from '../features/embed.ts';\nimport { progress } from '../output/progress.ts';\nimport { parseFile } from '../scan/index.ts';\nimport type { Store, VectorCandidate, VectorSimilar } from '../store/types.ts';\nimport { checkLanguageFit } from './langfit.ts';\nimport { getProvider } from './registry.ts';\nimport { STORE_DIMS } from './types.ts';\n\n// Slice + re-normalize (Matryoshka); optionally round through int8 storage. Exported for\n// benchmark/lib/embed.mjs, which scores the same lever math offline.\nexport function toStore(full: Float32Array, dims: number, int8: boolean): { v: Float32Array; scale: number } {\n const v = new Float32Array(dims);\n let norm = 0;\n for (let d = 0; d < dims; d++) norm += full[d] * full[d];\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] = full[d] / norm;\n if (!int8) return { v, scale: 1 };\n let max = 0;\n for (let d = 0; d < dims; d++) max = Math.max(max, Math.abs(v[d]));\n return { v, scale: max / 127 || 1 };\n}\n\n// Embed rows whose vector is NULL, re-deriving chunk text from the files through the\n// same parse + chunker that stored the rows.\nexport async function embedPending(store: Store, cfg: Config, baseDir: string): Promise<void> {\n const provider = await getProvider(cfg); // throws EMBED_DISABLED before touching the table\n const dirty = await store.vectors.pending();\n if (dirty.length === 0) return;\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n\n const byPath = new Map<string, number[]>();\n for (const row of dirty) {\n const list = byPath.get(row.path) ?? [];\n list.push(row.chunk);\n byPath.set(row.path, list);\n }\n\n const jobs: Array<{ path: string; chunk: number; text: string }> = [];\n for (const [path, chunkIdxs] of byPath) {\n let chunks: Chunk[];\n try {\n // presets/embed are irrelevant here -- re-deriving chunk text for a doc that already\n // has embeddings rows means the tree had an embedding model at reconcile time.\n chunks = parseFile({ relPath: path, absPath: join(baseDir, path), mtimeMs: 0, ctimeMs: 0, size: 0, presets: [], embed: true }, [embed], cfg).doc.extracted.embed as Chunk[];\n } catch {\n continue; // vanished since reconcile; the next reconcile removes its rows\n }\n for (const idx of chunkIdxs) if (chunks[idx]) jobs.push({ path, chunk: idx, text: chunks[idx].text });\n }\n\n // Over the exact texts about to be embedded, before any of them are: a mismatch fails\n // this run loudly instead of quietly storing vectors from the wrong model.\n await checkLanguageFit(\n store,\n provider,\n jobs.map((j) => j.text)\n );\n\n // The lazy build is the one long silence a first search hits (measured 23s at\n // 26k notes); progress makes it distinguishable from a hang.\n const report = progress('embedding chunks', jobs.length);\n for (let i = 0; i < jobs.length; i += provider.batchCap) {\n const batch = jobs.slice(i, i + provider.batchCap);\n const vectors = await provider.embedDocuments(batch.map((j) => j.text));\n await store.vectors.writeVectors(\n batch.map((job, j) => {\n const { v, scale } = toStore(vectors[j], storeDims, true);\n const q = new Int8Array(storeDims);\n for (let d = 0; d < storeDims; d++) q[d] = Math.round(v[d] / scale);\n return { path: job.path, chunk: job.chunk, scale, vector: Buffer.from(q.buffer) };\n })\n );\n report.tick(Math.min(i + provider.batchCap, jobs.length));\n }\n report.finish();\n}\n\n// Best chunk per file by cosine, its line range riding along; FTS5 operators are stripped as\n// lexical syntax. Similarity comes back because the fused score cannot express match quality,\n// and nearest-neighbour search always returns a neighbour however far away.\nexport async function semanticCandidates(store: Store, cfg: Config, terms: string, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n const baseDir = (cfg as Partial<ResolvedConfig>).baseDir;\n if (!baseDir) throw new SenseError('EMBED_MODEL', 'semantic expansion needs a config with baseDir (use loadConfig/open)');\n await embedPending(store, cfg, baseDir);\n\n const provider = await getProvider(cfg);\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n const text = (terms.match(/[\\p{L}\\p{N}]+/gu) ?? []).filter((t) => !['AND', 'OR', 'NOT', 'NEAR'].includes(t)).join(' ');\n const { v: qv } = toStore(await provider.embedQuery(text), storeDims, false);\n\n return store.vectors.candidates(qv, storeDims, fetch, allowed);\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasEmbedding(store: Store, path: string): Promise<boolean> {\n return store.vectors.hasVector(path);\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, one linear\n// scan of stored vectors.\nexport async function similarNotes(store: Store, _cfg: Config, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n return store.vectors.similar(path, opts);\n}\n"],"names":["embedPending","hasEmbedding","semanticCandidates","similarNotes","toStore","full","dims","int8","v","Float32Array","norm","d","Math","sqrt","scale","max","abs","store","cfg","baseDir","provider","dirty","storeDims","byPath","row","list","jobs","path","chunkIdxs","chunks","idx","report","i","batch","vectors","slice","batchCap","embedDocuments","map","j","text","writeVectors","job","q","Int8Array","round","chunk","vector","Buffer","from","buffer","tick","min","length","getProvider","pending","STORE_DIMS","Map","get","push","set","parseFile","relPath","absPath","join","mtimeMs","ctimeMs","size","presets","embed","doc","extracted","checkLanguageFit","progress","finish","terms","fetch","allowed","qv","SenseError","match","filter","t","includes","embedQuery","candidates","hasVector","_cfg","opts","similar"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/query.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Config, ResolvedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport type { Chunk } from '../features/embed.ts';\nimport { embed } from '../features/embed.ts';\nimport { progress } from '../output/progress.ts';\nimport { parseFile } from '../scan/index.ts';\nimport type { Store, VectorCandidate, VectorSimilar } from '../store/types.ts';\nimport { takeChunkText } from './handoff.ts';\nimport { checkLanguageFit } from './langfit.ts';\nimport { getProvider } from './registry.ts';\nimport { STORE_DIMS } from './types.ts';\n\n// Slice + re-normalize (Matryoshka); optionally round through int8 storage. Exported for\n// benchmark/lib/embed.mjs, which scores the same lever math offline.\nexport function toStore(full: Float32Array, dims: number, int8: boolean): { v: Float32Array; scale: number } {\n const v = new Float32Array(dims);\n let norm = 0;\n for (let d = 0; d < dims; d++) norm += full[d] * full[d];\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] = full[d] / norm;\n if (!int8) return { v, scale: 1 };\n let max = 0;\n for (let d = 0; d < dims; d++) max = Math.max(max, Math.abs(v[d]));\n return { v, scale: max / 127 || 1 };\n}\n\n// Embed rows whose vector is NULL. Reconcile hands its chunk text over in memory when it ran in\n// this process (handoff.ts); a row left pending by an earlier command re-derives from the file.\nexport async function embedPending(store: Store, cfg: Config, baseDir: string): Promise<void> {\n const provider = await getProvider(cfg); // throws EMBED_DISABLED before touching the table\n const dirty = await store.vectors.pending();\n if (dirty.length === 0) return;\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n\n const byPath = new Map<string, number[]>();\n for (const row of dirty) {\n const list = byPath.get(row.path) ?? [];\n list.push(row.chunk);\n byPath.set(row.path, list);\n }\n\n const textByPath = takeChunkText(store) ?? new Map<string, string[]>();\n\n const jobs: Array<{ path: string; chunk: number; text: string }> = [];\n for (const [path, chunkIdxs] of byPath) {\n const texts = textByPath.get(path);\n if (texts && chunkIdxs.every((idx) => idx < texts.length)) {\n // A stat, not a parse: a file that vanished since reconcile is skipped here even though its\n // text comes from memory, and the next reconcile removes its rows.\n if (!existsSync(join(baseDir, path))) continue;\n for (const idx of chunkIdxs) jobs.push({ path, chunk: idx, text: texts[idx] });\n continue;\n }\n // Reconcile ran in another process (`sense map` earlier, or a background `sense watch`), so\n // its chunk text is gone: re-derive this one file.\n let chunks: Chunk[];\n try {\n chunks = parseFile({ relPath: path, absPath: join(baseDir, path), mtimeMs: 0, ctimeMs: 0, size: 0, presets: [], embed: true }, [embed], cfg).doc.extracted.embed as Chunk[];\n } catch {\n continue; // vanished since reconcile; the next reconcile removes its rows\n }\n for (const idx of chunkIdxs) if (chunks[idx]) jobs.push({ path, chunk: idx, text: chunks[idx].text });\n }\n\n // Over the exact texts about to be embedded, before any of them are: a mismatch fails\n // this run loudly instead of quietly storing vectors from the wrong model.\n await checkLanguageFit(\n store,\n provider,\n jobs.map((j) => j.text)\n );\n\n // The lazy build is the one long silence a first search hits (measured 23s at\n // 26k notes); progress makes it distinguishable from a hang.\n const report = progress('embedding chunks', jobs.length);\n for (let i = 0; i < jobs.length; i += provider.batchCap) {\n const batch = jobs.slice(i, i + provider.batchCap);\n const vectors = await provider.embedDocuments(batch.map((j) => j.text));\n await store.vectors.writeVectors(\n batch.map((job, j) => {\n const { v, scale } = toStore(vectors[j], storeDims, true);\n const q = new Int8Array(storeDims);\n for (let d = 0; d < storeDims; d++) q[d] = Math.round(v[d] / scale);\n return { path: job.path, chunk: job.chunk, scale, vector: Buffer.from(q.buffer) };\n })\n );\n report.tick(Math.min(i + provider.batchCap, jobs.length));\n }\n report.finish();\n}\n\n// Best chunk per file by cosine, its line range riding along; FTS5 operators are stripped as\n// lexical syntax. Similarity comes back because the fused score cannot express match quality.\nexport async function semanticCandidates(store: Store, cfg: Config, terms: string, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n const baseDir = (cfg as Partial<ResolvedConfig>).baseDir;\n if (!baseDir) throw new SenseError('EMBED_MODEL', 'semantic expansion needs a config with baseDir (use loadConfig/open)');\n await embedPending(store, cfg, baseDir);\n\n const provider = await getProvider(cfg);\n const storeDims = Math.min(STORE_DIMS, provider.dims);\n const text = (terms.match(/[\\p{L}\\p{N}]+/gu) ?? []).filter((t) => !['AND', 'OR', 'NOT', 'NEAR'].includes(t)).join(' ');\n const { v: qv } = toStore(await provider.embedQuery(text), storeDims, false);\n\n return store.vectors.candidates(qv, storeDims, fetch, allowed);\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasEmbedding(store: Store, path: string): Promise<boolean> {\n return store.vectors.hasVector(path);\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, one linear\n// scan of stored vectors.\nexport async function similarNotes(store: Store, _cfg: Config, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n return store.vectors.similar(path, opts);\n}\n"],"names":["embedPending","hasEmbedding","semanticCandidates","similarNotes","toStore","full","dims","int8","v","Float32Array","norm","d","Math","sqrt","scale","max","abs","store","cfg","baseDir","takeChunkText","provider","dirty","storeDims","byPath","row","list","textByPath","jobs","report","i","batch","vectors","slice","batchCap","embedDocuments","map","j","text","writeVectors","job","q","Int8Array","round","path","chunk","vector","Buffer","from","buffer","tick","min","length","getProvider","pending","STORE_DIMS","Map","get","push","set","chunkIdxs","texts","every","idx","existsSync","join","chunks","parseFile","relPath","absPath","mtimeMs","ctimeMs","size","presets","embed","doc","extracted","checkLanguageFit","progress","finish","terms","fetch","allowed","qv","SenseError","match","filter","t","includes","embedQuery","candidates","hasVector","_cfg","opts","similar"],"mappings":"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"}
@@ -83,8 +83,7 @@ function getProvider(cfg) {
83
83
  var factory = REGISTRY[e.provider];
84
84
  if (!factory) throw new _errorsts.SenseError('EMBED_MODEL', 'embed.provider "'.concat(e.provider, '" has no provider implementation in this build'));
85
85
  // Every input that shapes the provider is in the key: two trees sharing an endpoint and
86
- // model but declaring different languages or reading different key env vars are two
87
- // providers, not one, however long a process lives.
86
+ // model but declaring different languages or key env vars are two providers, not one.
88
87
  var sig = JSON.stringify([
89
88
  e.provider,
90
89
  e.model,
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/registry.ts"],"sourcesContent":["import type { Config } from '../config/index.ts';\nimport { embedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { cohereProvider } from './cohere.ts';\nimport { openaiProvider } from './openai.ts';\nimport { staticProvider } from './static.ts';\nimport type { EmbedProvider } from './types.ts';\n\ntype ProviderFactory = (model: string, url: string | undefined, key: string | undefined) => Promise<EmbedProvider>;\n\n// One factory per wire protocol: adding a protocol is a new file plus an entry here, not\n// an edit to a dispatch ternary.\nconst REGISTRY: Record<string, ProviderFactory> = {\n static: (model) => staticProvider(model),\n openai: (model, url, key) => openaiProvider(model, url, key),\n cohere: (model, url, key) => cohereProvider(model, url, key),\n};\n\nconst providers = new Map<string, Promise<EmbedProvider>>();\n\nexport function getProvider(cfg: Config): Promise<EmbedProvider> {\n const e = embedConfig(cfg);\n if (!e) throw new SenseError('EMBED_DISABLED', 'this tree has no embedding model: add an \"embed\" block naming one to sense.config.json; a Hugging Face id fetches automatically at first use, or run `sense download` to prefetch it');\n const factory = REGISTRY[e.provider];\n if (!factory) throw new SenseError('EMBED_MODEL', `embed.provider \"${e.provider}\" has no provider implementation in this build`);\n // Every input that shapes the provider is in the key: two trees sharing an endpoint and\n // model but declaring different languages or reading different key env vars are two\n // providers, not one, however long a process lives.\n const sig = JSON.stringify([e.provider, e.model, e.url ?? '', e.key ?? '', e.languages ?? []]);\n let p = providers.get(sig);\n if (!p) {\n p = factory(e.model, e.url, e.key);\n // Owner-declared languages override a provider's own: the config is the one home for\n // what no model card can state (http models have no fetchable card here).\n if (e.languages) p = p.then((prov) => ({ ...prov, languages: e.languages }));\n providers.set(sig, p);\n // A rejected construction is evicted, so a transient failure retries instead of\n // poisoning this config for the process lifetime.\n p.catch(() => providers.delete(sig));\n }\n return p;\n}\n"],"names":["getProvider","REGISTRY","static","model","staticProvider","openai","url","key","openaiProvider","cohere","cohereProvider","providers","Map","cfg","e","embedConfig","SenseError","factory","provider","sig","JSON","stringify","languages","p","get","then","prov","set","catch","delete"],"mappings":";;;;+BAoBgBA;;;eAAAA;;;uBAnBY;wBACD;wBACI;wBACA;wBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAK/B,yFAAyF;AACzF,iCAAiC;AACjC,IAAMC,WAA4C;IAChDC,QAAQ,SAARA,QAASC;eAAUC,IAAAA,wBAAc,EAACD;;IAClCE,QAAQ,SAARA,OAASF,OAAOG,KAAKC;eAAQC,IAAAA,wBAAc,EAACL,OAAOG,KAAKC;;IACxDE,QAAQ,SAARA,OAASN,OAAOG,KAAKC;eAAQG,IAAAA,wBAAc,EAACP,OAAOG,KAAKC;;AAC1D;AAEA,IAAMI,YAAY,IAAIC;AAEf,SAASZ,YAAYa,GAAW;QAQYC,QAAaA,QAAaA;IAP3E,IAAMA,IAAIC,IAAAA,oBAAW,EAACF;IACtB,IAAI,CAACC,GAAG,MAAM,IAAIE,oBAAU,CAAC,kBAAkB;IAC/C,IAAMC,UAAUhB,QAAQ,CAACa,EAAEI,QAAQ,CAAC;IACpC,IAAI,CAACD,SAAS,MAAM,IAAID,oBAAU,CAAC,eAAe,AAAC,mBAA6B,OAAXF,EAAEI,QAAQ,EAAC;IAChF,wFAAwF;IACxF,oFAAoF;IACpF,oDAAoD;IACpD,IAAMC,MAAMC,KAAKC,SAAS,CAAC;QAACP,EAAEI,QAAQ;QAAEJ,EAAEX,KAAK;SAAEW,SAAAA,EAAER,GAAG,cAALQ,oBAAAA,SAAS;SAAIA,SAAAA,EAAEP,GAAG,cAALO,oBAAAA,SAAS;SAAIA,eAAAA,EAAEQ,SAAS,cAAXR,0BAAAA,eAAe,EAAE;KAAC;IAC7F,IAAIS,IAAIZ,UAAUa,GAAG,CAACL;IACtB,IAAI,CAACI,GAAG;QACNA,IAAIN,QAAQH,EAAEX,KAAK,EAAEW,EAAER,GAAG,EAAEQ,EAAEP,GAAG;QACjC,qFAAqF;QACrF,0EAA0E;QAC1E,IAAIO,EAAEQ,SAAS,EAAEC,IAAIA,EAAEE,IAAI,CAAC,SAACC;mBAAU,wCAAKA;gBAAMJ,WAAWR,EAAEQ,SAAS;;;QACxEX,UAAUgB,GAAG,CAACR,KAAKI;QACnB,gFAAgF;QAChF,kDAAkD;QAClDA,EAAEK,KAAK,CAAC;mBAAMjB,UAAUkB,MAAM,CAACV;;IACjC;IACA,OAAOI;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/registry.ts"],"sourcesContent":["import type { Config } from '../config/index.ts';\nimport { embedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { cohereProvider } from './cohere.ts';\nimport { openaiProvider } from './openai.ts';\nimport { staticProvider } from './static.ts';\nimport type { EmbedProvider } from './types.ts';\n\ntype ProviderFactory = (model: string, url: string | undefined, key: string | undefined) => Promise<EmbedProvider>;\n\n// One factory per wire protocol: adding a protocol is a new file plus an entry here, not\n// an edit to a dispatch ternary.\nconst REGISTRY: Record<string, ProviderFactory> = {\n static: (model) => staticProvider(model),\n openai: (model, url, key) => openaiProvider(model, url, key),\n cohere: (model, url, key) => cohereProvider(model, url, key),\n};\n\nconst providers = new Map<string, Promise<EmbedProvider>>();\n\nexport function getProvider(cfg: Config): Promise<EmbedProvider> {\n const e = embedConfig(cfg);\n if (!e) throw new SenseError('EMBED_DISABLED', 'this tree has no embedding model: add an \"embed\" block naming one to sense.config.json; a Hugging Face id fetches automatically at first use, or run `sense download` to prefetch it');\n const factory = REGISTRY[e.provider];\n if (!factory) throw new SenseError('EMBED_MODEL', `embed.provider \"${e.provider}\" has no provider implementation in this build`);\n // Every input that shapes the provider is in the key: two trees sharing an endpoint and\n // model but declaring different languages or key env vars are two providers, not one.\n const sig = JSON.stringify([e.provider, e.model, e.url ?? '', e.key ?? '', e.languages ?? []]);\n let p = providers.get(sig);\n if (!p) {\n p = factory(e.model, e.url, e.key);\n // Owner-declared languages override a provider's own: the config is the one home for\n // what no model card can state (http models have no fetchable card here).\n if (e.languages) p = p.then((prov) => ({ ...prov, languages: e.languages }));\n providers.set(sig, p);\n // A rejected construction is evicted, so a transient failure retries instead of\n // poisoning this config for the process lifetime.\n p.catch(() => providers.delete(sig));\n }\n return p;\n}\n"],"names":["getProvider","REGISTRY","static","model","staticProvider","openai","url","key","openaiProvider","cohere","cohereProvider","providers","Map","cfg","e","embedConfig","SenseError","factory","provider","sig","JSON","stringify","languages","p","get","then","prov","set","catch","delete"],"mappings":";;;;+BAoBgBA;;;eAAAA;;;uBAnBY;wBACD;wBACI;wBACA;wBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAK/B,yFAAyF;AACzF,iCAAiC;AACjC,IAAMC,WAA4C;IAChDC,QAAQ,SAARA,QAASC;eAAUC,IAAAA,wBAAc,EAACD;;IAClCE,QAAQ,SAARA,OAASF,OAAOG,KAAKC;eAAQC,IAAAA,wBAAc,EAACL,OAAOG,KAAKC;;IACxDE,QAAQ,SAARA,OAASN,OAAOG,KAAKC;eAAQG,IAAAA,wBAAc,EAACP,OAAOG,KAAKC;;AAC1D;AAEA,IAAMI,YAAY,IAAIC;AAEf,SAASZ,YAAYa,GAAW;QAOYC,QAAaA,QAAaA;IAN3E,IAAMA,IAAIC,IAAAA,oBAAW,EAACF;IACtB,IAAI,CAACC,GAAG,MAAM,IAAIE,oBAAU,CAAC,kBAAkB;IAC/C,IAAMC,UAAUhB,QAAQ,CAACa,EAAEI,QAAQ,CAAC;IACpC,IAAI,CAACD,SAAS,MAAM,IAAID,oBAAU,CAAC,eAAe,AAAC,mBAA6B,OAAXF,EAAEI,QAAQ,EAAC;IAChF,wFAAwF;IACxF,sFAAsF;IACtF,IAAMC,MAAMC,KAAKC,SAAS,CAAC;QAACP,EAAEI,QAAQ;QAAEJ,EAAEX,KAAK;SAAEW,SAAAA,EAAER,GAAG,cAALQ,oBAAAA,SAAS;SAAIA,SAAAA,EAAEP,GAAG,cAALO,oBAAAA,SAAS;SAAIA,eAAAA,EAAEQ,SAAS,cAAXR,0BAAAA,eAAe,EAAE;KAAC;IAC7F,IAAIS,IAAIZ,UAAUa,GAAG,CAACL;IACtB,IAAI,CAACI,GAAG;QACNA,IAAIN,QAAQH,EAAEX,KAAK,EAAEW,EAAER,GAAG,EAAEQ,EAAEP,GAAG;QACjC,qFAAqF;QACrF,0EAA0E;QAC1E,IAAIO,EAAEQ,SAAS,EAAEC,IAAIA,EAAEE,IAAI,CAAC,SAACC;mBAAU,wCAAKA;gBAAMJ,WAAWR,EAAEQ,SAAS;;;QACxEX,UAAUgB,GAAG,CAACR,KAAKI;QACnB,gFAAgF;QAChF,kDAAkD;QAClDA,EAAEK,KAAK,CAAC;mBAAMjB,UAAUkB,MAAM,CAACV;;IACjC;IACA,OAAOI;AACT"}
@@ -1,2 +1,2 @@
1
1
  import type { EmbedProvider } from './types.js';
2
- export declare function staticProvider(model: string): Promise<EmbedProvider>;
2
+ export declare function staticProvider(model: string, root?: string): Promise<EmbedProvider>;
@@ -1,2 +1,2 @@
1
1
  import type { EmbedProvider } from './types.js';
2
- export declare function staticProvider(model: string): Promise<EmbedProvider>;
2
+ export declare function staticProvider(model: string, root?: string): Promise<EmbedProvider>;
@@ -190,17 +190,15 @@ function _unsupported_iterable_to_array(o, minLen) {
190
190
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
191
191
  }
192
192
  var BATCH_CAP = 64;
193
- // @huggingface/tokenizers is a 540K static import; a top-level import put it on every command's
194
- // module graph regardless of whether the semantic path ran, shipped as the 0.17.0 regression.
195
- // Deferred to a synchronous require inside staticProvider so only the embed path pays for it.
193
+ // @huggingface/tokenizers is a 540K static import; a top-level import would put it on every
194
+ // command's module graph, so it's deferred to a synchronous require inside staticProvider.
196
195
  var _require = typeof require === 'undefined' ? _nodemodule.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require;
197
- function staticProvider(model) {
196
+ function staticProvider(model, root) {
198
197
  return _async_to_generator(function() {
199
198
  var _ref, _tokenizerJson_model, _tokenizerJson_model_vocab, _tokenizerJson_model1, dir, languages, cached, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, raw, headerLen, header, entry, spec, dims, dataStart, matrix, tokenizerJson, Tokenizer, tok, unkId;
200
199
  function one(text) {
201
- // The tokenizer yields undefined (not the unk id) for tokens outside the vocab; an
202
- // undefined id would index the matrix at NaN and poison the whole mean-pool -- and the
203
- // int8 conversion then stores the NaN vector as all zeros, silently. Keep integers only.
200
+ // The tokenizer yields undefined (not the unk id) for out-of-vocab tokens; unfiltered, it
201
+ // would index the matrix at NaN, and int8 conversion stores that NaN vector as all zeros.
204
202
  var ids = tok.encode(text, {
205
203
  add_special_tokens: false
206
204
  }).ids.filter(function(id) {
@@ -249,20 +247,20 @@ function staticProvider(model) {
249
247
  4,
250
248
  (0, _storets.downloadModel)(model, function(file, into) {
251
249
  return console.error("sense: fetching ".concat(model, "/").concat(file, " into ").concat(into));
252
- })
250
+ }, root)
253
251
  ];
254
252
  case 1:
255
253
  // Naming a HF id is consent: fetch whatever is missing now, announcing it on stderr.
256
254
  dir = _state.sent();
257
255
  // Cached beside the repo; a local model directory has no card to read, so it has none.
258
- cached = (0, _storets.readLanguages)(model);
256
+ cached = (0, _storets.readLanguages)(model, root);
259
257
  languages = cached && cached.length > 0 ? cached : undefined;
260
258
  return [
261
259
  3,
262
260
  3
263
261
  ];
264
262
  case 2:
265
- dir = (0, _storets.modelDir)(model);
263
+ dir = (0, _storets.modelDir)(model, root);
266
264
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
267
265
  try {
268
266
  for(_iterator = _storets.MODEL_FILES[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/static.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport Module from 'node:module';\nimport { join } from 'node:path';\nimport { SenseError } from '../errors.ts';\nimport { downloadModel, isDownloadable, MODEL_FILENAMES, MODEL_FILES, modelDir, readLanguages } from './store.ts';\nimport type { EmbedProvider } from './types.ts';\n\nconst BATCH_CAP = 64;\n\n// @huggingface/tokenizers is a 540K static import; a top-level import put it on every command's\n// module graph regardless of whether the semantic path ran, shipped as the 0.17.0 regression.\n// Deferred to a synchronous require inside staticProvider so only the embed path pays for it.\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Model2Vec safetensors + pure-JS tokenizer. Encode convention from model2vec/model.py: no\n// special tokens, drop unk ids, mean-pool, L2-normalize.\nexport async function staticProvider(model: string): Promise<EmbedProvider> {\n let dir: string;\n let languages: string[] | undefined;\n if (isDownloadable(model)) {\n // Naming a HF id is consent: fetch whatever is missing now, announcing it on stderr.\n dir = await downloadModel(model, (file, into) => console.error(`sense: fetching ${model}/${file} into ${into}`));\n // Cached beside the repo; a local model directory has no card to read, so it has none.\n const cached = readLanguages(model);\n languages = cached && cached.length > 0 ? cached : undefined;\n } else {\n dir = modelDir(model);\n for (const file of MODEL_FILES) {\n if (!existsSync(join(dir, file))) {\n throw new SenseError('EMBED_MODEL_MISSING', `embed model ${model} is not available (looked in ${dir}); expected ${MODEL_FILENAMES} in that directory`);\n }\n }\n }\n\n const raw = readFileSync(join(dir, 'model.safetensors'));\n const headerLen = Number(raw.readBigUInt64LE(0));\n const header = JSON.parse(raw.subarray(8, 8 + headerLen).toString('utf8')) as Record<string, { dtype: string; shape: number[]; data_offsets: number[] }>;\n const entry = Object.entries(header).find(([k]) => k !== '__metadata__');\n if (!entry || entry[1].dtype !== 'F32') throw new SenseError('EMBED_MODEL', `${model}: expected an F32 safetensors matrix`);\n const spec = entry[1];\n const dims = spec.shape[1];\n const dataStart = raw.byteOffset + 8 + headerLen + spec.data_offsets[0];\n const matrix = dataStart % 4 === 0 ? new Float32Array(raw.buffer, dataStart, spec.shape[0] * dims) : new Float32Array(raw.buffer.slice(dataStart, dataStart + spec.shape[0] * dims * 4));\n\n const tokenizerJson = JSON.parse(readFileSync(join(dir, 'tokenizer.json'), 'utf8'));\n const { Tokenizer } = _require('@huggingface/tokenizers') as typeof import('@huggingface/tokenizers');\n const tok = new Tokenizer(tokenizerJson, {});\n const unkId = tokenizerJson.model?.vocab?.[tokenizerJson.model?.unk_token] ?? -1;\n\n function one(text: string): Float32Array {\n // The tokenizer yields undefined (not the unk id) for tokens outside the vocab; an\n // undefined id would index the matrix at NaN and poison the whole mean-pool -- and the\n // int8 conversion then stores the NaN vector as all zeros, silently. Keep integers only.\n const ids = (tok.encode(text, { add_special_tokens: false }).ids as number[]).filter((id) => Number.isInteger(id) && id !== unkId);\n const v = new Float32Array(dims);\n if (ids.length === 0) return v;\n for (const id of ids) {\n const off = id * dims;\n for (let d = 0; d < dims; d++) v[d] += matrix[off + d];\n }\n let norm = 0;\n for (let d = 0; d < dims; d++) {\n v[d] /= ids.length;\n norm += v[d] * v[d];\n }\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] /= norm;\n return v;\n }\n\n // Symmetric model: document and query embedding are the same call.\n return { id: `static:${model}`, dims, batchCap: BATCH_CAP, languages, embedDocuments: async (texts) => texts.map(one), embedQuery: async (text) => one(text) };\n}\n"],"names":["staticProvider","BATCH_CAP","_require","require","Module","createRequire","model","tokenizerJson","dir","languages","cached","file","raw","headerLen","header","entry","spec","dims","dataStart","matrix","Tokenizer","tok","unkId","one","text","ids","encode","add_special_tokens","filter","id","Number","isInteger","v","Float32Array","length","off","d","norm","Math","sqrt","isDownloadable","downloadModel","into","console","error","readLanguages","undefined","modelDir","MODEL_FILES","existsSync","join","SenseError","MODEL_FILENAMES","readFileSync","readBigUInt64LE","JSON","parse","subarray","toString","Object","entries","find","k","dtype","shape","byteOffset","data_offsets","buffer","slice","vocab","unk_token","batchCap","embedDocuments","texts","map","embedQuery"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/static.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport Module from 'node:module';\nimport { join } from 'node:path';\nimport { SenseError } from '../errors.ts';\nimport { downloadModel, isDownloadable, MODEL_FILENAMES, MODEL_FILES, modelDir, readLanguages } from './store.ts';\nimport type { EmbedProvider } from './types.ts';\n\nconst BATCH_CAP = 64;\n\n// @huggingface/tokenizers is a 540K static import; a top-level import would put it on every\n// command's module graph, so it's deferred to a synchronous require inside staticProvider.\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Model2Vec safetensors + pure-JS tokenizer. Encode convention from model2vec/model.py: no\n// special tokens, drop unk ids, mean-pool, L2-normalize.\nexport async function staticProvider(model: string, root?: string): Promise<EmbedProvider> {\n let dir: string;\n let languages: string[] | undefined;\n if (isDownloadable(model)) {\n // Naming a HF id is consent: fetch whatever is missing now, announcing it on stderr.\n dir = await downloadModel(model, (file, into) => console.error(`sense: fetching ${model}/${file} into ${into}`), root);\n // Cached beside the repo; a local model directory has no card to read, so it has none.\n const cached = readLanguages(model, root);\n languages = cached && cached.length > 0 ? cached : undefined;\n } else {\n dir = modelDir(model, root);\n for (const file of MODEL_FILES) {\n if (!existsSync(join(dir, file))) {\n throw new SenseError('EMBED_MODEL_MISSING', `embed model ${model} is not available (looked in ${dir}); expected ${MODEL_FILENAMES} in that directory`);\n }\n }\n }\n\n const raw = readFileSync(join(dir, 'model.safetensors'));\n const headerLen = Number(raw.readBigUInt64LE(0));\n const header = JSON.parse(raw.subarray(8, 8 + headerLen).toString('utf8')) as Record<string, { dtype: string; shape: number[]; data_offsets: number[] }>;\n const entry = Object.entries(header).find(([k]) => k !== '__metadata__');\n if (!entry || entry[1].dtype !== 'F32') throw new SenseError('EMBED_MODEL', `${model}: expected an F32 safetensors matrix`);\n const spec = entry[1];\n const dims = spec.shape[1];\n const dataStart = raw.byteOffset + 8 + headerLen + spec.data_offsets[0];\n const matrix = dataStart % 4 === 0 ? new Float32Array(raw.buffer, dataStart, spec.shape[0] * dims) : new Float32Array(raw.buffer.slice(dataStart, dataStart + spec.shape[0] * dims * 4));\n\n const tokenizerJson = JSON.parse(readFileSync(join(dir, 'tokenizer.json'), 'utf8'));\n const { Tokenizer } = _require('@huggingface/tokenizers') as typeof import('@huggingface/tokenizers');\n const tok = new Tokenizer(tokenizerJson, {});\n const unkId = tokenizerJson.model?.vocab?.[tokenizerJson.model?.unk_token] ?? -1;\n\n function one(text: string): Float32Array {\n // The tokenizer yields undefined (not the unk id) for out-of-vocab tokens; unfiltered, it\n // would index the matrix at NaN, and int8 conversion stores that NaN vector as all zeros.\n const ids = (tok.encode(text, { add_special_tokens: false }).ids as number[]).filter((id) => Number.isInteger(id) && id !== unkId);\n const v = new Float32Array(dims);\n if (ids.length === 0) return v;\n for (const id of ids) {\n const off = id * dims;\n for (let d = 0; d < dims; d++) v[d] += matrix[off + d];\n }\n let norm = 0;\n for (let d = 0; d < dims; d++) {\n v[d] /= ids.length;\n norm += v[d] * v[d];\n }\n norm = Math.sqrt(norm) + 1e-32;\n for (let d = 0; d < dims; d++) v[d] /= norm;\n return v;\n }\n\n // Symmetric model: document and query embedding are the same call.\n return { id: `static:${model}`, dims, batchCap: BATCH_CAP, languages, embedDocuments: async (texts) => texts.map(one), embedQuery: async (text) => one(text) };\n}\n"],"names":["staticProvider","BATCH_CAP","_require","require","Module","createRequire","model","root","tokenizerJson","dir","languages","cached","file","raw","headerLen","header","entry","spec","dims","dataStart","matrix","Tokenizer","tok","unkId","one","text","ids","encode","add_special_tokens","filter","id","Number","isInteger","v","Float32Array","length","off","d","norm","Math","sqrt","isDownloadable","downloadModel","into","console","error","readLanguages","undefined","modelDir","MODEL_FILES","existsSync","join","SenseError","MODEL_FILENAMES","readFileSync","readBigUInt64LE","JSON","parse","subarray","toString","Object","entries","find","k","dtype","shape","byteOffset","data_offsets","buffer","slice","vocab","unk_token","batchCap","embedDocuments","texts","map","embedQuery"],"mappings":"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"}
@@ -4,5 +4,5 @@ export { hasModelFiles, isDownloadable, MODEL_FILENAMES, MODEL_FILES, modelDir,
4
4
  export declare function modelPresent(cfg: Config): boolean;
5
5
  type ResolvedEmbedConfig = NonNullable<ReturnType<typeof embedConfig>>;
6
6
  export declare function localModelMissing(e: ResolvedEmbedConfig | null): e is ResolvedEmbedConfig;
7
- export declare function downloadModelRevision(model: string, sha: string, onFile?: (file: string, dir: string) => void): Promise<string>;
8
- export declare function downloadModel(model: string, onFile?: (file: string, dir: string) => void): Promise<string>;
7
+ export declare function downloadModelRevision(model: string, sha: string, onFile?: (file: string, dir: string) => void, root?: string): Promise<string>;
8
+ export declare function downloadModel(model: string, onFile?: (file: string, dir: string) => void, root?: string): Promise<string>;
@@ -4,5 +4,5 @@ export { hasModelFiles, isDownloadable, MODEL_FILENAMES, MODEL_FILES, modelDir,
4
4
  export declare function modelPresent(cfg: Config): boolean;
5
5
  type ResolvedEmbedConfig = NonNullable<ReturnType<typeof embedConfig>>;
6
6
  export declare function localModelMissing(e: ResolvedEmbedConfig | null): e is ResolvedEmbedConfig;
7
- export declare function downloadModelRevision(model: string, sha: string, onFile?: (file: string, dir: string) => void): Promise<string>;
8
- export declare function downloadModel(model: string, onFile?: (file: string, dir: string) => void): Promise<string>;
7
+ export declare function downloadModelRevision(model: string, sha: string, onFile?: (file: string, dir: string) => void, root?: string): Promise<string>;
8
+ export declare function downloadModel(model: string, onFile?: (file: string, dir: string) => void, root?: string): Promise<string>;
@@ -195,13 +195,15 @@ function localModelMissing(e) {
195
195
  }
196
196
  // `main` resolves to a sha once per model: a recorded ref pins until its snapshot is
197
197
  // removed, so only the first need for an id ever costs this HEAD request.
198
- function resolveSha(model) {
199
- return _async_to_generator(function() {
200
- var existing, url, res, err, sha;
198
+ function resolveSha(_0) {
199
+ return _async_to_generator(function(model) {
200
+ var root, existing, url, res, err, sha;
201
+ var _arguments = arguments;
201
202
  return _ts_generator(this, function(_state) {
202
203
  switch(_state.label){
203
204
  case 0:
204
- existing = (0, _identityts.readRef)(model);
205
+ root = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : _identityts.DEFAULT_MODELS_ROOT;
206
+ existing = (0, _identityts.readRef)(model, root);
205
207
  if (existing) return [
206
208
  2,
207
209
  existing
@@ -234,19 +236,17 @@ function resolveSha(model) {
234
236
  case 4:
235
237
  sha = res.headers.get('x-repo-commit');
236
238
  if (!sha) throw new _errorsts.SenseError('EMBED_MODEL', "".concat(url, ": response carried no x-repo-commit header"));
237
- (0, _identityts.writeRef)(model, sha);
239
+ (0, _identityts.writeRef)(model, sha, root);
238
240
  return [
239
241
  2,
240
242
  sha
241
243
  ];
242
244
  }
243
245
  });
244
- })();
246
+ }).apply(this, arguments);
245
247
  }
246
- // cardData.language is the structured field (verified live: minishlab/potion-retrieval-32M has
247
- // neither this nor any language tag, so it stays silent; potion-multilingual-128M carries an
248
- // array here). Tags are a fallback for cards that only tag languages, filtered to recognized
249
- // codes so an unrelated short tag (format markers etc.) is never mistaken for one.
248
+ // cardData.language is the structured field; tags are a fallback for cards that only tag
249
+ // languages, filtered to recognized codes so an unrelated short tag is never mistaken for one.
250
250
  function languagesFromCard(info) {
251
251
  var _info_tags;
252
252
  var _info_cardData;
@@ -258,21 +258,26 @@ function languagesFromCard(info) {
258
258
  var tagLangs = ((_info_tags = info.tags) !== null && _info_tags !== void 0 ? _info_tags : []).filter(_languagests.isKnownLanguageTag);
259
259
  return tagLangs.length > 0 ? tagLangs : undefined;
260
260
  }
261
- // Best-effort, cached forever once resolved (even to "none"): unlike model weights, missing or
262
- // unreachable metadata is not an error -- it just means the language-fit check stays off.
263
- function ensureLanguages(model) {
264
- return _async_to_generator(function() {
265
- var _languagesFromCard, measured, res, unused, info, unused1;
261
+ // Unreachable metadata is not an error, only the language-fit check staying off, but it says so:
262
+ // the check that keeps a misfit model loud cannot itself go quiet (PRINCIPLES: no-silent-modes).
263
+ function cardUnreadable(model) {
264
+ console.error("sense: could not read the model card for ".concat(model, "; the language-fit check is off until it resolves (retries on next run, or run `sense download`)"));
265
+ }
266
+ function ensureLanguages(_0) {
267
+ return _async_to_generator(function(model) {
268
+ var root, _languagesFromCard, measured, res, unused, info, unused1;
269
+ var _arguments = arguments;
266
270
  return _ts_generator(this, function(_state) {
267
271
  switch(_state.label){
268
272
  case 0:
269
- if ((0, _nodefs.existsSync)((0, _identityts.languagesPath)(model))) return [
273
+ root = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : _identityts.DEFAULT_MODELS_ROOT;
274
+ if ((0, _nodefs.existsSync)((0, _identityts.languagesPath)(model, root))) return [
270
275
  2
271
276
  ];
272
277
  // A measured entry needs no card and no network, and stays deterministic offline.
273
278
  measured = _languagests.MEASURED_MODEL_LANGUAGES[model];
274
279
  if (measured) {
275
- (0, _identityts.writeLanguages)(model, measured);
280
+ (0, _identityts.writeLanguages)(model, measured, root);
276
281
  return [
277
282
  2
278
283
  ];
@@ -297,13 +302,17 @@ function ensureLanguages(model) {
297
302
  ];
298
303
  case 3:
299
304
  unused = _state.sent();
305
+ cardUnreadable(model);
300
306
  return [
301
307
  2
302
308
  ];
303
309
  case 4:
304
- if (!res.ok) return [
305
- 2
306
- ];
310
+ if (!res.ok) {
311
+ cardUnreadable(model);
312
+ return [
313
+ 2
314
+ ];
315
+ }
307
316
  _state.label = 5;
308
317
  case 5:
309
318
  _state.trys.push([
@@ -324,17 +333,18 @@ function ensureLanguages(model) {
324
333
  ];
325
334
  case 7:
326
335
  unused1 = _state.sent();
336
+ cardUnreadable(model);
327
337
  return [
328
338
  2
329
339
  ];
330
340
  case 8:
331
- (0, _identityts.writeLanguages)(model, (_languagesFromCard = languagesFromCard(info)) !== null && _languagesFromCard !== void 0 ? _languagesFromCard : []);
341
+ (0, _identityts.writeLanguages)(model, (_languagesFromCard = languagesFromCard(info)) !== null && _languagesFromCard !== void 0 ? _languagesFromCard : [], root);
332
342
  return [
333
343
  2
334
344
  ];
335
345
  }
336
346
  });
337
- })();
347
+ }).apply(this, arguments);
338
348
  }
339
349
  function fetchToFile(url, dest) {
340
350
  return _async_to_generator(function() {
@@ -384,13 +394,15 @@ function fetchToFile(url, dest) {
384
394
  });
385
395
  })();
386
396
  }
387
- function downloadModelRevision(model, sha, onFile) {
388
- return _async_to_generator(function() {
389
- var dir, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, err;
397
+ function downloadModelRevision(_0, _1, _2) {
398
+ return _async_to_generator(function(model, sha, onFile) {
399
+ var root, dir, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, err;
400
+ var _arguments = arguments;
390
401
  return _ts_generator(this, function(_state) {
391
402
  switch(_state.label){
392
403
  case 0:
393
- dir = (0, _identityts.snapshotDir)(model, sha);
404
+ root = _arguments.length > 3 && _arguments[3] !== void 0 ? _arguments[3] : _identityts.DEFAULT_MODELS_ROOT;
405
+ dir = (0, _identityts.snapshotDir)(model, sha, root);
394
406
  (0, _nodefs.mkdirSync)(dir, {
395
407
  recursive: true
396
408
  });
@@ -462,20 +474,22 @@ function downloadModelRevision(model, sha, onFile) {
462
474
  ];
463
475
  }
464
476
  });
465
- })();
477
+ }).apply(this, arguments);
466
478
  }
467
- function downloadModel(model, onFile) {
468
- return _async_to_generator(function() {
469
- var sha;
479
+ function downloadModel(_0, _1) {
480
+ return _async_to_generator(function(model, onFile) {
481
+ var root, sha;
482
+ var _arguments = arguments;
470
483
  return _ts_generator(this, function(_state) {
471
484
  switch(_state.label){
472
485
  case 0:
486
+ root = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : _identityts.DEFAULT_MODELS_ROOT;
473
487
  if (!(0, _identityts.isDownloadable)(model)) {
474
488
  throw new _errorsts.SenseError('EMBED_MODEL', 'embed.model "'.concat(model, '" is a local path, not a Hugging Face model id, so there is nothing to download; put model.safetensors and tokenizer.json in that directory, or name a model id like "minishlab/potion-retrieval-32M"'));
475
489
  }
476
490
  return [
477
491
  4,
478
- resolveSha(model)
492
+ resolveSha(model, root)
479
493
  ];
480
494
  case 1:
481
495
  sha = _state.sent();
@@ -483,16 +497,16 @@ function downloadModel(model, onFile) {
483
497
  // construction and an explicit prefetch both end up with a cached language verdict.
484
498
  return [
485
499
  4,
486
- ensureLanguages(model)
500
+ ensureLanguages(model, root)
487
501
  ];
488
502
  case 2:
489
503
  _state.sent();
490
504
  return [
491
505
  2,
492
- downloadModelRevision(model, sha, onFile)
506
+ downloadModelRevision(model, sha, onFile, root)
493
507
  ];
494
508
  }
495
509
  });
496
- })();
510
+ }).apply(this, arguments);
497
511
  }
498
512
  /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }