@nhtio/adk 1.20260607.2 → 1.20260609.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 (501) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/batteries/embeddings/openai/adapter.cjs +1 -1
  3. package/batteries/embeddings/openai/adapter.mjs +1 -1
  4. package/batteries/embeddings/openai/exceptions.cjs +1 -1
  5. package/batteries/embeddings/openai/exceptions.mjs +1 -1
  6. package/batteries/embeddings/openai/types.d.ts +7 -0
  7. package/batteries/embeddings/webllm/adapter.cjs +1 -1
  8. package/batteries/embeddings/webllm/adapter.mjs +1 -1
  9. package/batteries/embeddings/webllm/exceptions.cjs +1 -1
  10. package/batteries/embeddings/webllm/exceptions.mjs +1 -1
  11. package/batteries/llm/chat_common/helpers.d.ts +165 -0
  12. package/batteries/llm/chat_common/types.d.ts +309 -0
  13. package/batteries/llm/index.d.ts +5 -0
  14. package/batteries/llm/ollama/adapter.cjs +736 -0
  15. package/batteries/llm/ollama/adapter.cjs.map +1 -0
  16. package/batteries/llm/ollama/adapter.d.ts +64 -0
  17. package/batteries/llm/ollama/adapter.mjs +734 -0
  18. package/batteries/llm/ollama/adapter.mjs.map +1 -0
  19. package/batteries/llm/ollama/exceptions.cjs +105 -0
  20. package/batteries/llm/ollama/exceptions.cjs.map +1 -0
  21. package/batteries/llm/ollama/exceptions.d.ts +112 -0
  22. package/batteries/llm/ollama/exceptions.mjs +96 -0
  23. package/batteries/llm/ollama/exceptions.mjs.map +1 -0
  24. package/batteries/llm/ollama/helpers.cjs +487 -0
  25. package/batteries/llm/ollama/helpers.cjs.map +1 -0
  26. package/batteries/llm/ollama/helpers.d.ts +158 -0
  27. package/batteries/llm/ollama/helpers.mjs +450 -0
  28. package/batteries/llm/ollama/helpers.mjs.map +1 -0
  29. package/batteries/llm/ollama/index.d.ts +29 -0
  30. package/batteries/llm/ollama/types.cjs +2 -0
  31. package/batteries/llm/ollama/types.d.ts +334 -0
  32. package/batteries/llm/ollama/types.mjs +0 -0
  33. package/batteries/llm/ollama/validation.cjs +130 -0
  34. package/batteries/llm/ollama/validation.cjs.map +1 -0
  35. package/batteries/llm/ollama/validation.d.ts +31 -0
  36. package/batteries/llm/ollama/validation.mjs +127 -0
  37. package/batteries/llm/ollama/validation.mjs.map +1 -0
  38. package/batteries/llm/ollama.cjs +54 -0
  39. package/batteries/llm/ollama.mjs +6 -0
  40. package/batteries/llm/openai_chat_completions/adapter.cjs +36 -19
  41. package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
  42. package/batteries/llm/openai_chat_completions/adapter.mjs +23 -6
  43. package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
  44. package/batteries/llm/openai_chat_completions/exceptions.cjs +1 -1
  45. package/batteries/llm/openai_chat_completions/exceptions.mjs +1 -1
  46. package/batteries/llm/openai_chat_completions/helpers.cjs +80 -320
  47. package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -1
  48. package/batteries/llm/openai_chat_completions/helpers.d.ts +68 -144
  49. package/batteries/llm/openai_chat_completions/helpers.mjs +40 -280
  50. package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -1
  51. package/batteries/llm/openai_chat_completions/types.d.ts +273 -181
  52. package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
  53. package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
  54. package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
  55. package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
  56. package/batteries/llm/openai_chat_completions.cjs +29 -28
  57. package/batteries/llm/openai_chat_completions.mjs +2 -1
  58. package/batteries/llm/webllm_chat_completions/adapter.cjs +38 -19
  59. package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
  60. package/batteries/llm/webllm_chat_completions/adapter.d.ts +18 -0
  61. package/batteries/llm/webllm_chat_completions/adapter.mjs +25 -6
  62. package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
  63. package/batteries/llm/webllm_chat_completions/exceptions.cjs +1 -1
  64. package/batteries/llm/webllm_chat_completions/exceptions.mjs +1 -1
  65. package/batteries/llm/webllm_chat_completions/helpers.cjs +29 -28
  66. package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -1
  67. package/batteries/llm/webllm_chat_completions/types.d.ts +21 -0
  68. package/batteries/llm/webllm_chat_completions/validation.cjs +13 -1
  69. package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
  70. package/batteries/llm/webllm_chat_completions/validation.d.ts +12 -0
  71. package/batteries/llm/webllm_chat_completions/validation.mjs +13 -1
  72. package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
  73. package/batteries/llm/webllm_chat_completions.cjs +29 -28
  74. package/batteries/llm/webllm_chat_completions.mjs +2 -1
  75. package/batteries/llm.cjs +44 -28
  76. package/batteries/llm.mjs +9 -4
  77. package/batteries/storage/flydrive.cjs +1 -1
  78. package/batteries/storage/flydrive.mjs +1 -1
  79. package/batteries/storage/in_memory/index.d.ts +1 -1
  80. package/batteries/storage/in_memory.cjs +2 -2
  81. package/batteries/storage/in_memory.cjs.map +1 -1
  82. package/batteries/storage/in_memory.mjs +2 -2
  83. package/batteries/storage/in_memory.mjs.map +1 -1
  84. package/batteries/storage/opfs/index.d.ts +19 -0
  85. package/batteries/storage/opfs.cjs +1 -1
  86. package/batteries/storage/opfs.cjs.map +1 -1
  87. package/batteries/storage/opfs.mjs +1 -1
  88. package/batteries/storage/opfs.mjs.map +1 -1
  89. package/batteries/tools/color.cjs +3 -2
  90. package/batteries/tools/color.cjs.map +1 -1
  91. package/batteries/tools/color.mjs +3 -2
  92. package/batteries/tools/color.mjs.map +1 -1
  93. package/batteries/tools/comparison.cjs +4 -3
  94. package/batteries/tools/comparison.cjs.map +1 -1
  95. package/batteries/tools/comparison.mjs +4 -3
  96. package/batteries/tools/comparison.mjs.map +1 -1
  97. package/batteries/tools/data_structure.cjs +30 -10
  98. package/batteries/tools/data_structure.cjs.map +1 -1
  99. package/batteries/tools/data_structure.mjs +30 -10
  100. package/batteries/tools/data_structure.mjs.map +1 -1
  101. package/batteries/tools/datetime_extended.cjs +5 -10
  102. package/batteries/tools/datetime_extended.cjs.map +1 -1
  103. package/batteries/tools/datetime_extended.mjs +5 -10
  104. package/batteries/tools/datetime_extended.mjs.map +1 -1
  105. package/batteries/tools/datetime_math.cjs +2 -2
  106. package/batteries/tools/datetime_math.mjs +2 -2
  107. package/batteries/tools/encoding.cjs +13 -4
  108. package/batteries/tools/encoding.cjs.map +1 -1
  109. package/batteries/tools/encoding.mjs +13 -4
  110. package/batteries/tools/encoding.mjs.map +1 -1
  111. package/batteries/tools/formatting.cjs +4 -4
  112. package/batteries/tools/formatting.cjs.map +1 -1
  113. package/batteries/tools/formatting.mjs +4 -4
  114. package/batteries/tools/formatting.mjs.map +1 -1
  115. package/batteries/tools/geo_basics.cjs +2 -2
  116. package/batteries/tools/geo_basics.mjs +2 -2
  117. package/batteries/tools/index.d.ts +1 -0
  118. package/batteries/tools/math.cjs +10 -8
  119. package/batteries/tools/math.cjs.map +1 -1
  120. package/batteries/tools/math.mjs +10 -8
  121. package/batteries/tools/math.mjs.map +1 -1
  122. package/batteries/tools/memory.cjs +5 -5
  123. package/batteries/tools/memory.mjs +5 -5
  124. package/batteries/tools/parsing.cjs +9 -5
  125. package/batteries/tools/parsing.cjs.map +1 -1
  126. package/batteries/tools/parsing.mjs +9 -5
  127. package/batteries/tools/parsing.mjs.map +1 -1
  128. package/batteries/tools/retrievables.cjs +4 -4
  129. package/batteries/tools/retrievables.mjs +4 -4
  130. package/batteries/tools/searxng/exceptions.d.ts +21 -0
  131. package/batteries/tools/searxng/index.d.ts +150 -0
  132. package/batteries/tools/searxng.cjs +5 -0
  133. package/batteries/tools/searxng.mjs +2 -0
  134. package/batteries/tools/standing_instructions.cjs +4 -4
  135. package/batteries/tools/standing_instructions.mjs +4 -4
  136. package/batteries/tools/statistics.cjs +54 -43
  137. package/batteries/tools/statistics.cjs.map +1 -1
  138. package/batteries/tools/statistics.mjs +54 -43
  139. package/batteries/tools/statistics.mjs.map +1 -1
  140. package/batteries/tools/string_processing.cjs +5 -5
  141. package/batteries/tools/string_processing.cjs.map +1 -1
  142. package/batteries/tools/string_processing.mjs +5 -5
  143. package/batteries/tools/string_processing.mjs.map +1 -1
  144. package/batteries/tools/structured_data.cjs +8 -13
  145. package/batteries/tools/structured_data.cjs.map +1 -1
  146. package/batteries/tools/structured_data.mjs +8 -13
  147. package/batteries/tools/structured_data.mjs.map +1 -1
  148. package/batteries/tools/text_analysis.cjs +3 -3
  149. package/batteries/tools/text_analysis.mjs +3 -3
  150. package/batteries/tools/text_comparison.cjs +2 -2
  151. package/batteries/tools/text_comparison.mjs +2 -2
  152. package/batteries/tools/time.cjs +2 -2
  153. package/batteries/tools/time.mjs +2 -2
  154. package/batteries/tools/unit_conversion.cjs +10 -8
  155. package/batteries/tools/unit_conversion.cjs.map +1 -1
  156. package/batteries/tools/unit_conversion.mjs +10 -8
  157. package/batteries/tools/unit_conversion.mjs.map +1 -1
  158. package/batteries/tools.cjs +3 -0
  159. package/batteries/tools.mjs +2 -1
  160. package/batteries/vector/arangodb/index.d.ts +2 -0
  161. package/batteries/vector/arangodb.cjs +2 -1
  162. package/batteries/vector/arangodb.cjs.map +1 -1
  163. package/batteries/vector/arangodb.mjs +2 -1
  164. package/batteries/vector/arangodb.mjs.map +1 -1
  165. package/batteries/vector/builder.cjs +31 -0
  166. package/batteries/vector/builder.cjs.map +1 -1
  167. package/batteries/vector/builder.d.ts +58 -0
  168. package/batteries/vector/builder.mjs +31 -0
  169. package/batteries/vector/builder.mjs.map +1 -1
  170. package/batteries/vector/chroma/index.d.ts +4 -0
  171. package/batteries/vector/chroma.cjs +3 -0
  172. package/batteries/vector/chroma.cjs.map +1 -1
  173. package/batteries/vector/chroma.mjs +3 -0
  174. package/batteries/vector/chroma.mjs.map +1 -1
  175. package/batteries/vector/clickhouse/index.d.ts +2 -0
  176. package/batteries/vector/clickhouse.cjs +2 -1
  177. package/batteries/vector/clickhouse.cjs.map +1 -1
  178. package/batteries/vector/clickhouse.mjs +2 -1
  179. package/batteries/vector/clickhouse.mjs.map +1 -1
  180. package/batteries/vector/cloudflare/index.d.ts +2 -0
  181. package/batteries/vector/cloudflare.cjs +2 -1
  182. package/batteries/vector/cloudflare.cjs.map +1 -1
  183. package/batteries/vector/cloudflare.mjs +2 -1
  184. package/batteries/vector/cloudflare.mjs.map +1 -1
  185. package/batteries/vector/conformance/index.d.ts +22 -0
  186. package/batteries/vector/conformance.cjs +22 -0
  187. package/batteries/vector/conformance.cjs.map +1 -1
  188. package/batteries/vector/conformance.mjs +22 -0
  189. package/batteries/vector/conformance.mjs.map +1 -1
  190. package/batteries/vector/contract.cjs +22 -0
  191. package/batteries/vector/contract.cjs.map +1 -1
  192. package/batteries/vector/contract.d.ts +51 -0
  193. package/batteries/vector/contract.mjs +22 -0
  194. package/batteries/vector/contract.mjs.map +1 -1
  195. package/batteries/vector/couchbase/index.d.ts +2 -0
  196. package/batteries/vector/couchbase.cjs +2 -1
  197. package/batteries/vector/couchbase.cjs.map +1 -1
  198. package/batteries/vector/couchbase.mjs +2 -1
  199. package/batteries/vector/couchbase.mjs.map +1 -1
  200. package/batteries/vector/duckdb/index.d.ts +2 -0
  201. package/batteries/vector/duckdb.cjs +2 -1
  202. package/batteries/vector/duckdb.cjs.map +1 -1
  203. package/batteries/vector/duckdb.mjs +2 -1
  204. package/batteries/vector/duckdb.mjs.map +1 -1
  205. package/batteries/vector/elasticsearch/index.d.ts +2 -0
  206. package/batteries/vector/elasticsearch.cjs +2 -1
  207. package/batteries/vector/elasticsearch.cjs.map +1 -1
  208. package/batteries/vector/elasticsearch.mjs +2 -1
  209. package/batteries/vector/elasticsearch.mjs.map +1 -1
  210. package/batteries/vector/exceptions.cjs +1 -1
  211. package/batteries/vector/exceptions.mjs +1 -1
  212. package/batteries/vector/factory.cjs +6 -0
  213. package/batteries/vector/factory.cjs.map +1 -1
  214. package/batteries/vector/factory.d.ts +14 -0
  215. package/batteries/vector/factory.mjs +6 -0
  216. package/batteries/vector/factory.mjs.map +1 -1
  217. package/batteries/vector/filters.cjs +22 -1
  218. package/batteries/vector/filters.cjs.map +1 -1
  219. package/batteries/vector/filters.d.ts +38 -0
  220. package/batteries/vector/filters.mjs +22 -1
  221. package/batteries/vector/filters.mjs.map +1 -1
  222. package/batteries/vector/helpers.cjs +13 -0
  223. package/batteries/vector/helpers.cjs.map +1 -1
  224. package/batteries/vector/helpers.d.ts +14 -0
  225. package/batteries/vector/helpers.mjs +13 -0
  226. package/batteries/vector/helpers.mjs.map +1 -1
  227. package/batteries/vector/hnswlib/index.d.ts +2 -0
  228. package/batteries/vector/hnswlib.cjs +2 -1
  229. package/batteries/vector/hnswlib.cjs.map +1 -1
  230. package/batteries/vector/hnswlib.mjs +2 -1
  231. package/batteries/vector/hnswlib.mjs.map +1 -1
  232. package/batteries/vector/in_memory/index.d.ts +1 -0
  233. package/batteries/vector/in_memory.cjs +1 -0
  234. package/batteries/vector/in_memory.cjs.map +1 -1
  235. package/batteries/vector/in_memory.mjs +1 -0
  236. package/batteries/vector/in_memory.mjs.map +1 -1
  237. package/batteries/vector/lancedb/index.d.ts +2 -0
  238. package/batteries/vector/lancedb.cjs +2 -1
  239. package/batteries/vector/lancedb.cjs.map +1 -1
  240. package/batteries/vector/lancedb.mjs +2 -1
  241. package/batteries/vector/lancedb.mjs.map +1 -1
  242. package/batteries/vector/mariadb/index.d.ts +2 -0
  243. package/batteries/vector/mariadb.cjs +2 -1
  244. package/batteries/vector/mariadb.cjs.map +1 -1
  245. package/batteries/vector/mariadb.mjs +2 -1
  246. package/batteries/vector/mariadb.mjs.map +1 -1
  247. package/batteries/vector/meilisearch/index.d.ts +2 -0
  248. package/batteries/vector/meilisearch.cjs +2 -1
  249. package/batteries/vector/meilisearch.cjs.map +1 -1
  250. package/batteries/vector/meilisearch.mjs +2 -1
  251. package/batteries/vector/meilisearch.mjs.map +1 -1
  252. package/batteries/vector/migrate.cjs +18 -1
  253. package/batteries/vector/migrate.cjs.map +1 -1
  254. package/batteries/vector/migrate.d.ts +31 -0
  255. package/batteries/vector/migrate.mjs +18 -1
  256. package/batteries/vector/migrate.mjs.map +1 -1
  257. package/batteries/vector/milvus/index.d.ts +5 -0
  258. package/batteries/vector/milvus.cjs +4 -0
  259. package/batteries/vector/milvus.cjs.map +1 -1
  260. package/batteries/vector/milvus.mjs +4 -0
  261. package/batteries/vector/milvus.mjs.map +1 -1
  262. package/batteries/vector/mongodb/index.d.ts +2 -0
  263. package/batteries/vector/mongodb.cjs +2 -1
  264. package/batteries/vector/mongodb.cjs.map +1 -1
  265. package/batteries/vector/mongodb.mjs +2 -1
  266. package/batteries/vector/mongodb.mjs.map +1 -1
  267. package/batteries/vector/neo4j/index.d.ts +2 -0
  268. package/batteries/vector/neo4j.cjs +2 -1
  269. package/batteries/vector/neo4j.cjs.map +1 -1
  270. package/batteries/vector/neo4j.mjs +2 -1
  271. package/batteries/vector/neo4j.mjs.map +1 -1
  272. package/batteries/vector/opensearch/index.d.ts +2 -0
  273. package/batteries/vector/opensearch.cjs +2 -1
  274. package/batteries/vector/opensearch.cjs.map +1 -1
  275. package/batteries/vector/opensearch.mjs +2 -1
  276. package/batteries/vector/opensearch.mjs.map +1 -1
  277. package/batteries/vector/oracle23ai/index.d.ts +2 -0
  278. package/batteries/vector/oracle23ai.cjs +2 -1
  279. package/batteries/vector/oracle23ai.cjs.map +1 -1
  280. package/batteries/vector/oracle23ai.mjs +2 -1
  281. package/batteries/vector/oracle23ai.mjs.map +1 -1
  282. package/batteries/vector/orama/index.d.ts +1 -0
  283. package/batteries/vector/orama.cjs +1 -0
  284. package/batteries/vector/orama.cjs.map +1 -1
  285. package/batteries/vector/orama.mjs +1 -0
  286. package/batteries/vector/orama.mjs.map +1 -1
  287. package/batteries/vector/pgvector/index.d.ts +9 -2
  288. package/batteries/vector/pgvector.cjs +4 -0
  289. package/batteries/vector/pgvector.cjs.map +1 -1
  290. package/batteries/vector/pgvector.mjs +4 -0
  291. package/batteries/vector/pgvector.mjs.map +1 -1
  292. package/batteries/vector/pinecone/index.d.ts +5 -0
  293. package/batteries/vector/pinecone.cjs +3 -1
  294. package/batteries/vector/pinecone.cjs.map +1 -1
  295. package/batteries/vector/pinecone.mjs +3 -1
  296. package/batteries/vector/pinecone.mjs.map +1 -1
  297. package/batteries/vector/plan.d.ts +27 -0
  298. package/batteries/vector/qdrant/index.d.ts +5 -0
  299. package/batteries/vector/qdrant.cjs +4 -0
  300. package/batteries/vector/qdrant.cjs.map +1 -1
  301. package/batteries/vector/qdrant.mjs +4 -0
  302. package/batteries/vector/qdrant.mjs.map +1 -1
  303. package/batteries/vector/redis/index.d.ts +2 -0
  304. package/batteries/vector/redis.cjs +2 -1
  305. package/batteries/vector/redis.cjs.map +1 -1
  306. package/batteries/vector/redis.mjs +2 -1
  307. package/batteries/vector/redis.mjs.map +1 -1
  308. package/batteries/vector/retrievable.cjs +9 -1
  309. package/batteries/vector/retrievable.cjs.map +1 -1
  310. package/batteries/vector/retrievable.mjs +9 -1
  311. package/batteries/vector/retrievable.mjs.map +1 -1
  312. package/batteries/vector/retrievable_glue.d.ts +21 -0
  313. package/batteries/vector/s3vectors/index.d.ts +2 -0
  314. package/batteries/vector/s3vectors.cjs +2 -1
  315. package/batteries/vector/s3vectors.cjs.map +1 -1
  316. package/batteries/vector/s3vectors.mjs +2 -1
  317. package/batteries/vector/s3vectors.mjs.map +1 -1
  318. package/batteries/vector/schema.cjs +28 -0
  319. package/batteries/vector/schema.cjs.map +1 -1
  320. package/batteries/vector/schema.d.ts +39 -0
  321. package/batteries/vector/schema.mjs +28 -0
  322. package/batteries/vector/schema.mjs.map +1 -1
  323. package/batteries/vector/solr/index.d.ts +2 -0
  324. package/batteries/vector/solr.cjs +2 -1
  325. package/batteries/vector/solr.cjs.map +1 -1
  326. package/batteries/vector/solr.mjs +2 -1
  327. package/batteries/vector/solr.mjs.map +1 -1
  328. package/batteries/vector/sqlite_vec/index.d.ts +6 -3
  329. package/batteries/vector/sqlite_vec.cjs +2 -0
  330. package/batteries/vector/sqlite_vec.cjs.map +1 -1
  331. package/batteries/vector/sqlite_vec.mjs +2 -0
  332. package/batteries/vector/sqlite_vec.mjs.map +1 -1
  333. package/batteries/vector/surrealdb/index.d.ts +2 -0
  334. package/batteries/vector/surrealdb.cjs +2 -1
  335. package/batteries/vector/surrealdb.cjs.map +1 -1
  336. package/batteries/vector/surrealdb.mjs +2 -1
  337. package/batteries/vector/surrealdb.mjs.map +1 -1
  338. package/batteries/vector/types.d.ts +27 -0
  339. package/batteries/vector/typesense/index.d.ts +2 -0
  340. package/batteries/vector/typesense.cjs +2 -1
  341. package/batteries/vector/typesense.cjs.map +1 -1
  342. package/batteries/vector/typesense.mjs +2 -1
  343. package/batteries/vector/typesense.mjs.map +1 -1
  344. package/batteries/vector/validation.cjs +14 -0
  345. package/batteries/vector/validation.cjs.map +1 -1
  346. package/batteries/vector/validation.d.ts +14 -0
  347. package/batteries/vector/validation.mjs +14 -0
  348. package/batteries/vector/validation.mjs.map +1 -1
  349. package/batteries/vector/vector_store_constructor.cjs +1 -1
  350. package/batteries/vector/vector_store_constructor.cjs.map +1 -1
  351. package/batteries/vector/vector_store_constructor.d.ts +1 -1
  352. package/batteries/vector/vector_store_constructor.mjs +1 -1
  353. package/batteries/vector/vector_store_constructor.mjs.map +1 -1
  354. package/batteries/vector/vespa/index.d.ts +2 -0
  355. package/batteries/vector/vespa.cjs +2 -1
  356. package/batteries/vector/vespa.cjs.map +1 -1
  357. package/batteries/vector/vespa.mjs +2 -1
  358. package/batteries/vector/vespa.mjs.map +1 -1
  359. package/batteries/vector/weaviate/index.d.ts +2 -0
  360. package/batteries/vector/weaviate.cjs +2 -1
  361. package/batteries/vector/weaviate.cjs.map +1 -1
  362. package/batteries/vector/weaviate.mjs +2 -1
  363. package/batteries/vector/weaviate.mjs.map +1 -1
  364. package/batteries.cjs +46 -28
  365. package/batteries.mjs +10 -5
  366. package/{common-BT0nfCi9.mjs → common-DYDUi99O.mjs} +9 -9
  367. package/common-DYDUi99O.mjs.map +1 -0
  368. package/{common-Cj8TaQ9U.js → common-DZl3ADJs.js} +9 -9
  369. package/common-DZl3ADJs.js.map +1 -0
  370. package/common.cjs +7 -7
  371. package/common.d.ts +1 -1
  372. package/common.mjs +7 -7
  373. package/{dispatch_runner-DPcS7Y_M.mjs → dispatch_runner--ZhdDWRZ.mjs} +27 -5
  374. package/{dispatch_runner-DPcS7Y_M.mjs.map → dispatch_runner--ZhdDWRZ.mjs.map} +1 -1
  375. package/{dispatch_runner-BHBNupqp.js → dispatch_runner-nHDKkxye.js} +27 -5
  376. package/{dispatch_runner-BHBNupqp.js.map → dispatch_runner-nHDKkxye.js.map} +1 -1
  377. package/dispatch_runner.cjs +1 -1
  378. package/dispatch_runner.d.ts +1 -1
  379. package/dispatch_runner.mjs +1 -1
  380. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +1 -0
  381. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs.map +1 -1
  382. package/eslint/rules/artifact_tool_forbids_artifact_constructor.d.ts +1 -0
  383. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs +1 -0
  384. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs.map +1 -1
  385. package/eslint/rules/no_model_in_tool_handler.cjs +1 -0
  386. package/eslint/rules/no_model_in_tool_handler.cjs.map +1 -1
  387. package/eslint/rules/no_model_in_tool_handler.d.ts +1 -0
  388. package/eslint/rules/no_model_in_tool_handler.mjs +1 -0
  389. package/eslint/rules/no_model_in_tool_handler.mjs.map +1 -1
  390. package/eslint/rules/require_validator_any_required.cjs +1 -0
  391. package/eslint/rules/require_validator_any_required.cjs.map +1 -1
  392. package/eslint/rules/require_validator_any_required.d.ts +1 -0
  393. package/eslint/rules/require_validator_any_required.mjs +1 -0
  394. package/eslint/rules/require_validator_any_required.mjs.map +1 -1
  395. package/eslint/rules/thought_payload_requires_replay_tag.cjs +1 -0
  396. package/eslint/rules/thought_payload_requires_replay_tag.cjs.map +1 -1
  397. package/eslint/rules/thought_payload_requires_replay_tag.d.ts +1 -0
  398. package/eslint/rules/thought_payload_requires_replay_tag.mjs +1 -0
  399. package/eslint/rules/thought_payload_requires_replay_tag.mjs.map +1 -1
  400. package/eslint/rules/token_encoding_requires_context_window.cjs +1 -0
  401. package/eslint/rules/token_encoding_requires_context_window.cjs.map +1 -1
  402. package/eslint/rules/token_encoding_requires_context_window.d.ts +1 -0
  403. package/eslint/rules/token_encoding_requires_context_window.mjs +1 -0
  404. package/eslint/rules/token_encoding_requires_context_window.mjs.map +1 -1
  405. package/eslint.cjs +1 -1
  406. package/eslint.mjs +1 -1
  407. package/{exceptions-BeWH2FwP.mjs → exceptions-BDhN0Xzr.mjs} +3 -2
  408. package/exceptions-BDhN0Xzr.mjs.map +1 -0
  409. package/{exceptions-CitH5wZI.js → exceptions-BRXrUKiW.js} +3 -2
  410. package/exceptions-BRXrUKiW.js.map +1 -0
  411. package/exceptions.cjs +2 -2
  412. package/exceptions.mjs +2 -2
  413. package/factories.cjs +1 -1
  414. package/factories.mjs +1 -1
  415. package/forge.cjs +4 -4
  416. package/forge.d.ts +1 -1
  417. package/forge.mjs +4 -4
  418. package/guards.cjs +9 -9
  419. package/guards.mjs +9 -9
  420. package/helpers-DSTFxTiC.js +497 -0
  421. package/helpers-DSTFxTiC.js.map +1 -0
  422. package/helpers-xhrQbMAG.mjs +306 -0
  423. package/helpers-xhrQbMAG.mjs.map +1 -0
  424. package/index.cjs +13 -13
  425. package/index.mjs +13 -13
  426. package/lib/classes/base_exception.d.ts +1 -0
  427. package/lib/classes/media.d.ts +10 -0
  428. package/lib/classes/retrievable.d.ts +1 -1
  429. package/lib/classes/spooled_json_artifact.d.ts +1 -1
  430. package/lib/classes/spooled_markdown_artifact.d.ts +1 -0
  431. package/lib/classes/tokenizable.d.ts +3 -0
  432. package/lib/classes/tool.d.ts +8 -0
  433. package/lib/classes/turn_gate.d.ts +6 -0
  434. package/lib/dispatch_runner.d.ts +4 -32
  435. package/lib/helpers/bignum.cjs +82 -0
  436. package/lib/helpers/bignum.cjs.map +1 -0
  437. package/lib/helpers/bignum.d.ts +52 -0
  438. package/lib/helpers/bignum.mjs +74 -0
  439. package/lib/helpers/bignum.mjs.map +1 -0
  440. package/lib/turn_runner.d.ts +1 -1
  441. package/lib/types/dispatch_runner.d.ts +83 -0
  442. package/lib/utils/exceptions.d.ts +1 -1
  443. package/lib/utils/retry.cjs.map +1 -1
  444. package/lib/utils/retry.d.ts +2 -0
  445. package/lib/utils/retry.mjs.map +1 -1
  446. package/mcp/adk-docs-corpus.json +1 -1
  447. package/package.json +264 -224
  448. package/{runtime-j92CNi5z.mjs → runtime-Bz5zA8wc.mjs} +2 -2
  449. package/{runtime-j92CNi5z.mjs.map → runtime-Bz5zA8wc.mjs.map} +1 -1
  450. package/{runtime-MFFcJrRv.js → runtime-DslE1aBw.js} +2 -2
  451. package/{runtime-MFFcJrRv.js.map → runtime-DslE1aBw.js.map} +1 -1
  452. package/searxng-Bkrwhwhw.js +269 -0
  453. package/searxng-Bkrwhwhw.js.map +1 -0
  454. package/searxng-CyA-nEu5.mjs +257 -0
  455. package/searxng-CyA-nEu5.mjs.map +1 -0
  456. package/skills/adk-assembly/SKILL.md +2 -2
  457. package/{spooled_artifact-CHoZgWwI.mjs → spooled_artifact-7eePq7JA.mjs} +5 -5
  458. package/{spooled_artifact-CHoZgWwI.mjs.map → spooled_artifact-7eePq7JA.mjs.map} +1 -1
  459. package/{spooled_artifact-BTq6Nzfy.js → spooled_artifact-DX8LLyUX.js} +5 -5
  460. package/{spooled_artifact-BTq6Nzfy.js.map → spooled_artifact-DX8LLyUX.js.map} +1 -1
  461. package/spooled_artifact.cjs +2 -2
  462. package/spooled_artifact.mjs +2 -2
  463. package/{spooled_markdown_artifact-CALSDxIx.js → spooled_markdown_artifact-ClX72lek.js} +4 -4
  464. package/spooled_markdown_artifact-ClX72lek.js.map +1 -0
  465. package/{spooled_markdown_artifact-Ci5UL7l4.mjs → spooled_markdown_artifact-wkrBF3oX.mjs} +4 -4
  466. package/spooled_markdown_artifact-wkrBF3oX.mjs.map +1 -0
  467. package/{thought-D34QQZZ9.mjs → thought-B_vxAiKU.mjs} +5 -5
  468. package/{thought-D34QQZZ9.mjs.map → thought-B_vxAiKU.mjs.map} +1 -1
  469. package/{thought-BbwhJ1wb.js → thought-DLwpF7MI.js} +5 -5
  470. package/{thought-BbwhJ1wb.js.map → thought-DLwpF7MI.js.map} +1 -1
  471. package/{tool-CVyZkFC7.js → tool-D5WGVIcI.js} +4 -4
  472. package/{tool-CVyZkFC7.js.map → tool-D5WGVIcI.js.map} +1 -1
  473. package/{tool-CMhaDRNd.mjs → tool-wMYMVl60.mjs} +4 -4
  474. package/{tool-CMhaDRNd.mjs.map → tool-wMYMVl60.mjs.map} +1 -1
  475. package/{tool_call-CV5qVNlb.mjs → tool_call-B4-_-vjG.mjs} +5 -5
  476. package/tool_call-B4-_-vjG.mjs.map +1 -0
  477. package/{tool_call-Db68hB7y.js → tool_call-DixVlW40.js} +5 -5
  478. package/tool_call-DixVlW40.js.map +1 -0
  479. package/{tool_registry-D1pSSlsd.mjs → tool_registry-791Vrjtf.mjs} +4 -3
  480. package/tool_registry-791Vrjtf.mjs.map +1 -0
  481. package/{tool_registry-DYUYqXvo.js → tool_registry-CKJPze3j.js} +4 -3
  482. package/tool_registry-CKJPze3j.js.map +1 -0
  483. package/{turn_runner-DqWHNP80.js → turn_runner-HXImLGIn.js} +7 -7
  484. package/turn_runner-HXImLGIn.js.map +1 -0
  485. package/{turn_runner-fg1Wc3dK.mjs → turn_runner-ZyYO-Kti.mjs} +7 -7
  486. package/turn_runner-ZyYO-Kti.mjs.map +1 -0
  487. package/turn_runner.cjs +1 -1
  488. package/turn_runner.mjs +1 -1
  489. package/types.d.ts +1 -1
  490. package/common-BT0nfCi9.mjs.map +0 -1
  491. package/common-Cj8TaQ9U.js.map +0 -1
  492. package/exceptions-BeWH2FwP.mjs.map +0 -1
  493. package/exceptions-CitH5wZI.js.map +0 -1
  494. package/spooled_markdown_artifact-CALSDxIx.js.map +0 -1
  495. package/spooled_markdown_artifact-Ci5UL7l4.mjs.map +0 -1
  496. package/tool_call-CV5qVNlb.mjs.map +0 -1
  497. package/tool_call-Db68hB7y.js.map +0 -1
  498. package/tool_registry-D1pSSlsd.mjs.map +0 -1
  499. package/tool_registry-DYUYqXvo.js.map +0 -1
  500. package/turn_runner-DqWHNP80.js.map +0 -1
  501. package/turn_runner-fg1Wc3dK.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"arangodb.mjs","names":["#opts","#db","#aql","#ensure","#dims","#indexed","#ensureVectorIndex","#parseMeta","#project"],"sources":["../../../src/batteries/vector/arangodb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/arangodb\n *\n * ArangoDB adapter (experimental vector index, 3.12.4+). Each collection is an ArangoDB\n * document collection keyed by `_key`; a `vector` index on `vec` enables KNN via\n * `APPROX_NEAR_COSINE` / `APPROX_NEAR_L2`. Metadata is a JSON string attribute filtered with\n * the neutral filter tree's JS reference evaluator for exact cross-adapter parity.\n *\n * Driver: `arangojs` (pure JS). Requires the server started with\n * `--experimental-vector-index=true`. All values are passed as AQL bind parameters.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\n E_VECTOR_STORE_COLLECTION_FAILED,\n E_VECTOR_STORE_UPSERT_FAILED,\n E_VECTOR_STORE_SEARCH_FAILED,\n E_VECTOR_STORE_DELETE_FAILED,\n E_VECTOR_STORE_DIMENSION_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_OPERATION,\n} from '../exceptions'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n VectorMatch,\n VectorStoreCapabilities,\n BaseVectorStoreOptions,\n VectorMetadata,\n} from '../types'\n\nexport interface ArangoDBVectorStoreOptions extends BaseVectorStoreOptions {\n connection: {\n url: string\n username?: string\n password?: string\n database?: string\n nLists?: number\n }\n}\n\nconst getArango = async () => {\n try {\n const mod = await import('arangojs')\n return mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['arangojs'])\n }\n}\n\nexport class ArangoDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Document writes are synchronous (visible on resolve). The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #aql: any | null = null\n #dims: Map<string, number> = new Map()\n // ArangoDB's IVF vector index can't be created on an empty collection (\"not ready\") and\n // needs nLists <= doc count. We therefore create the index lazily after the first upsert.\n #indexed: Set<string> = new Set()\n\n get #opts(): ArangoDBVectorStoreOptions {\n return this.options as ArangoDBVectorStoreOptions\n }\n\n static isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n\n async connect(): Promise<void> {\n if (this.#db) return\n const arango = await getArango()\n this.#aql = arango.aql\n const c = this.#opts.connection\n const dbName = c.database ?? 'vector'\n try {\n const auth = c.username ? { username: c.username, password: c.password ?? '' } : undefined\n const sys = new arango.Database({ url: c.url, auth })\n const exists = await sys.listDatabases().then((dbs: string[]) => dbs.includes(dbName))\n if (!exists) {\n await sys.createDatabase(dbName)\n }\n this.#db = new arango.Database({ url: c.url, databaseName: dbName, auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n this.#aql = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n try {\n const col = db.collection(spec.collection)\n const exists = await col.exists()\n if (exists && !ifNotExists) {\n await col.drop()\n this.#indexed.delete(spec.collection)\n }\n if (!(await col.exists())) {\n await col.create()\n this.#indexed.delete(spec.collection)\n }\n // The vector index is created lazily on first upsert (see #ensureVectorIndex): ArangoDB\n // rejects creating it on an empty collection (\"vector index not ready\").\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n // Create the IVF vector index once the collection has data (idempotent per collection).\n async #ensureVectorIndex(collection: string): Promise<void> {\n if (this.#indexed.has(collection)) return\n const db = await this.#ensure()\n const col = db.collection(collection)\n const metric = this.#opts.metric ?? 'cosine'\n const dim = this.#dims.get(collection) ?? this.#opts.dimensions\n if (dim === undefined) return\n try {\n await col.ensureIndex({\n type: 'vector',\n fields: ['vec'],\n params: {\n metric: metric === 'euclidean' ? 'l2' : 'cosine',\n dimension: dim,\n nLists: this.#opts.connection.nLists ?? 1,\n },\n })\n this.#indexed.add(collection)\n } catch {\n // If it still isn't ready (too few docs), leave it; executeSearch falls back to a\n // brute-force AQL scan so correctness holds regardless of the index.\n }\n }\n\n async dropCollection(collection: string, ifExists: boolean): Promise<void> {\n const db = await this.#ensure()\n try {\n const col = db.collection(collection)\n if (await col.exists()) {\n await col.drop()\n } else if (!ifExists) {\n throw new Error('collection not found: ' + collection)\n }\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const db = await this.#ensure()\n try {\n return await db.collection(collection).exists()\n } catch {\n return false\n }\n }\n\n async renameCollection(_from: string, _to: string): Promise<void> {\n throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'arangodb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const col = db.collection(plan.collection)\n for (const r of plan.records) {\n let vector = r.vector\n if (!vector && r.document) {\n const [v] = await this.encode([r.document], 'document')\n vector = v\n }\n if (!vector) {\n throw new E_VECTOR_STORE_UPSERT_FAILED(['Record missing vector and document'])\n }\n if (expected !== undefined && vector.length !== expected) {\n throw new E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length])\n }\n const doc = {\n _key: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n await col.save(doc, { overwriteMode: 'replace' })\n }\n // Now that the collection has data, ensure the IVF vector index exists.\n await this.#ensureVectorIndex(plan.collection)\n } catch (err) {\n if (\n isInstanceOf(err, 'E_VECTOR_STORE_DIMENSION_MISMATCH', E_VECTOR_STORE_DIMENSION_MISMATCH) ||\n isInstanceOf(err, 'E_VECTOR_STORE_UPSERT_FAILED', E_VECTOR_STORE_UPSERT_FAILED)\n ) {\n throw err\n }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const db = await this.#ensure()\n const aql = this.#aql\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n if (plan.near) {\n if ('vector' in plan.near) {\n queryVector = plan.near.vector\n } else if ('serverText' in plan.near) {\n const [v] = await this.encode([plan.near.serverText], 'query')\n queryVector = v\n } else if ('id' in plan.near) {\n const col = db.collection(plan.collection)\n try {\n const doc = await col.document(plan.near.id)\n queryVector = doc.vec as number[]\n } catch {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n let rows: any[]\n if (queryVector) {\n // Use the exact AQL distance functions (COSINE_SIMILARITY / L2_DISTANCE) rather than the\n // APPROX_NEAR_* index functions: they need no index, are always correct, and avoid\n // ArangoDB's IVF \"not ready\" / nLists-vs-doc-count constraints. The IVF index is still\n // created lazily on upsert for production-scale ANN; here correctness comes first.\n const useL2 = metric === 'euclidean'\n const fn = useL2 ? 'L2_DISTANCE' : 'COSINE_SIMILARITY'\n const dir = useL2 ? 'ASC' : 'DESC'\n const k = plan.filter ? 100000 : plan.topK + offset\n const query =\n `FOR d IN @@col ` +\n `LET __score = ${fn}(d.vec, @qv) ` +\n `SORT __score ${dir} LIMIT @k ` +\n `RETURN { id: d._key, vec: d.vec, document: d.document, metadata: d.metadata, score: __score }`\n const cursor = await db.query(query, {\n '@col': plan.collection,\n 'qv': queryVector,\n k,\n })\n rows = await cursor.all()\n const filtered = plan.filter\n ? rows.filter((row) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row) => this.#project(row, plan, true))\n } else {\n const cursor = await db.query(\n aql`FOR d IN ${db.collection(plan.collection)} RETURN { id: d._key, vec: d.vec, document: d.document, metadata: d.metadata }`\n )\n rows = await cursor.all()\n const filtered = plan.filter\n ? rows.filter((row) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // APPROX_NEAR_COSINE returns cosine similarity in [0,1]; L2 returns a distance.\n const m = this.#opts.metric ?? 'cosine'\n out.score = m === 'euclidean' ? 1 / (1 + Number(row.score)) : Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n const aql = this.#aql\n try {\n const col = db.collection(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n await col.removeAll(plan.ids).catch(async () => {\n for (const id of plan.ids!) await col.remove(id).catch(() => undefined)\n })\n } else if (plan.filter) {\n const cursor = await db.query(\n aql`FOR d IN ${col} RETURN { id: d._key, metadata: d.metadata }`\n )\n const rows = await cursor.all()\n const targets = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n await col.removeAll(targets).catch(async () => {\n for (const id of targets) await col.remove(id).catch(() => undefined)\n })\n }\n } else {\n await col.truncate()\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"arangodb.mjs","names":["#opts","#db","#aql","#ensure","#dims","#indexed","#ensureVectorIndex","#parseMeta","#project"],"sources":["../../../src/batteries/vector/arangodb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/arangodb\n *\n * ArangoDB adapter (experimental vector index, 3.12.4+). Each collection is an ArangoDB\n * document collection keyed by `_key`; a `vector` index on `vec` enables KNN via\n * `APPROX_NEAR_COSINE` / `APPROX_NEAR_L2`. Metadata is a JSON string attribute filtered with\n * the neutral filter tree's JS reference evaluator for exact cross-adapter parity.\n *\n * Driver: `arangojs` (pure JS). Requires the server started with\n * `--experimental-vector-index=true`. All values are passed as AQL bind parameters.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\n E_VECTOR_STORE_COLLECTION_FAILED,\n E_VECTOR_STORE_UPSERT_FAILED,\n E_VECTOR_STORE_SEARCH_FAILED,\n E_VECTOR_STORE_DELETE_FAILED,\n E_VECTOR_STORE_DIMENSION_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_OPERATION,\n} from '../exceptions'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n VectorMatch,\n VectorStoreCapabilities,\n BaseVectorStoreOptions,\n VectorMetadata,\n} from '../types'\n\nexport interface ArangoDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: {\n url: string\n username?: string\n password?: string\n database?: string\n nLists?: number\n }\n}\n\nconst getArango = async () => {\n try {\n const mod = await import('arangojs')\n return mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['arangojs'])\n }\n}\n\nexport class ArangoDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Document writes are synchronous (visible on resolve). The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #aql: any | null = null\n #dims: Map<string, number> = new Map()\n // ArangoDB's IVF vector index can't be created on an empty collection (\"not ready\") and\n // needs nLists <= doc count. We therefore create the index lazily after the first upsert.\n #indexed: Set<string> = new Set()\n\n get #opts(): ArangoDBVectorStoreOptions {\n return this.options as ArangoDBVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\n static isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n\n async connect(): Promise<void> {\n if (this.#db) return\n const arango = await getArango()\n this.#aql = arango.aql\n const c = this.#opts.connection\n const dbName = c.database ?? 'vector'\n try {\n const auth = c.username ? { username: c.username, password: c.password ?? '' } : undefined\n const sys = new arango.Database({ url: c.url, auth })\n const exists = await sys.listDatabases().then((dbs: string[]) => dbs.includes(dbName))\n if (!exists) {\n await sys.createDatabase(dbName)\n }\n this.#db = new arango.Database({ url: c.url, databaseName: dbName, auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n this.#aql = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n try {\n const col = db.collection(spec.collection)\n const exists = await col.exists()\n if (exists && !ifNotExists) {\n await col.drop()\n this.#indexed.delete(spec.collection)\n }\n if (!(await col.exists())) {\n await col.create()\n this.#indexed.delete(spec.collection)\n }\n // The vector index is created lazily on first upsert (see #ensureVectorIndex): ArangoDB\n // rejects creating it on an empty collection (\"vector index not ready\").\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n // Create the IVF vector index once the collection has data (idempotent per collection).\n async #ensureVectorIndex(collection: string): Promise<void> {\n if (this.#indexed.has(collection)) return\n const db = await this.#ensure()\n const col = db.collection(collection)\n const metric = this.#opts.metric ?? 'cosine'\n const dim = this.#dims.get(collection) ?? this.#opts.dimensions\n if (dim === undefined) return\n try {\n await col.ensureIndex({\n type: 'vector',\n fields: ['vec'],\n params: {\n metric: metric === 'euclidean' ? 'l2' : 'cosine',\n dimension: dim,\n nLists: this.#opts.connection.nLists ?? 1,\n },\n })\n this.#indexed.add(collection)\n } catch {\n // If it still isn't ready (too few docs), leave it; executeSearch falls back to a\n // brute-force AQL scan so correctness holds regardless of the index.\n }\n }\n\n async dropCollection(collection: string, ifExists: boolean): Promise<void> {\n const db = await this.#ensure()\n try {\n const col = db.collection(collection)\n if (await col.exists()) {\n await col.drop()\n } else if (!ifExists) {\n throw new Error('collection not found: ' + collection)\n }\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const db = await this.#ensure()\n try {\n return await db.collection(collection).exists()\n } catch {\n return false\n }\n }\n\n async renameCollection(_from: string, _to: string): Promise<void> {\n throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'arangodb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const col = db.collection(plan.collection)\n for (const r of plan.records) {\n let vector = r.vector\n if (!vector && r.document) {\n const [v] = await this.encode([r.document], 'document')\n vector = v\n }\n if (!vector) {\n throw new E_VECTOR_STORE_UPSERT_FAILED(['Record missing vector and document'])\n }\n if (expected !== undefined && vector.length !== expected) {\n throw new E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length])\n }\n const doc = {\n _key: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n await col.save(doc, { overwriteMode: 'replace' })\n }\n // Now that the collection has data, ensure the IVF vector index exists.\n await this.#ensureVectorIndex(plan.collection)\n } catch (err) {\n if (\n isInstanceOf(err, 'E_VECTOR_STORE_DIMENSION_MISMATCH', E_VECTOR_STORE_DIMENSION_MISMATCH) ||\n isInstanceOf(err, 'E_VECTOR_STORE_UPSERT_FAILED', E_VECTOR_STORE_UPSERT_FAILED)\n ) {\n throw err\n }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const db = await this.#ensure()\n const aql = this.#aql\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n if (plan.near) {\n if ('vector' in plan.near) {\n queryVector = plan.near.vector\n } else if ('serverText' in plan.near) {\n const [v] = await this.encode([plan.near.serverText], 'query')\n queryVector = v\n } else if ('id' in plan.near) {\n const col = db.collection(plan.collection)\n try {\n const doc = await col.document(plan.near.id)\n queryVector = doc.vec as number[]\n } catch {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n let rows: any[]\n if (queryVector) {\n // Use the exact AQL distance functions (COSINE_SIMILARITY / L2_DISTANCE) rather than the\n // APPROX_NEAR_* index functions: they need no index, are always correct, and avoid\n // ArangoDB's IVF \"not ready\" / nLists-vs-doc-count constraints. The IVF index is still\n // created lazily on upsert for production-scale ANN; here correctness comes first.\n const useL2 = metric === 'euclidean'\n const fn = useL2 ? 'L2_DISTANCE' : 'COSINE_SIMILARITY'\n const dir = useL2 ? 'ASC' : 'DESC'\n const k = plan.filter ? 100000 : plan.topK + offset\n const query =\n `FOR d IN @@col ` +\n `LET __score = ${fn}(d.vec, @qv) ` +\n `SORT __score ${dir} LIMIT @k ` +\n `RETURN { id: d._key, vec: d.vec, document: d.document, metadata: d.metadata, score: __score }`\n const cursor = await db.query(query, {\n '@col': plan.collection,\n 'qv': queryVector,\n k,\n })\n rows = await cursor.all()\n const filtered = plan.filter\n ? rows.filter((row) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row) => this.#project(row, plan, true))\n } else {\n const cursor = await db.query(\n aql`FOR d IN ${db.collection(plan.collection)} RETURN { id: d._key, vec: d.vec, document: d.document, metadata: d.metadata }`\n )\n rows = await cursor.all()\n const filtered = plan.filter\n ? rows.filter((row) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // APPROX_NEAR_COSINE returns cosine similarity in [0,1]; L2 returns a distance.\n const m = this.#opts.metric ?? 'cosine'\n out.score = m === 'euclidean' ? 1 / (1 + Number(row.score)) : Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n const aql = this.#aql\n try {\n const col = db.collection(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n await col.removeAll(plan.ids).catch(async () => {\n for (const id of plan.ids!) await col.remove(id).catch(() => undefined)\n })\n } else if (plan.filter) {\n const cursor = await db.query(\n aql`FOR d IN ${col} RETURN { id: d._key, metadata: d.metadata }`\n )\n const rows = await cursor.all()\n const targets = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n await col.removeAll(targets).catch(async () => {\n for (const id of targets) await col.remove(id).catch(() => undefined)\n })\n }\n } else {\n await col.truncate()\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
@@ -118,15 +118,19 @@ var FilterBuilder = class FilterBuilder {
118
118
  }
119
119
  return this.orWhere(field, "ne", value);
120
120
  }
121
+ /** AND the condition that `field`'s value is one of `values`. */
121
122
  whereIn(field, values) {
122
123
  return this.where(field, "in", values);
123
124
  }
125
+ /** AND the condition that `field`'s value is none of `values`. */
124
126
  whereNotIn(field, values) {
125
127
  return this.where(field, "nin", values);
126
128
  }
129
+ /** AND the condition that `field` is absent (does not exist). */
127
130
  whereNull(field) {
128
131
  return this.where(field, "exists", false);
129
132
  }
133
+ /** AND the condition that `field` is present (exists). */
130
134
  whereExists(field) {
131
135
  return this.where(field, "exists", true);
132
136
  }
@@ -181,21 +185,44 @@ var VectorQueryBuilder = class extends FilterBuilder {
181
185
  this.#collection = collection;
182
186
  this.#topK = defaultTopK;
183
187
  }
188
+ /**
189
+ * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the
190
+ * other `near*` clauses.
191
+ *
192
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
193
+ */
184
194
  nearVector(vector) {
185
195
  if (this.#near !== void 0) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
186
196
  this.#near = { vector };
187
197
  return this;
188
198
  }
199
+ /**
200
+ * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive
201
+ * with the other `near*` clauses.
202
+ *
203
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
204
+ */
189
205
  nearText(text) {
190
206
  if (this.#near !== void 0) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
191
207
  this.#near = { serverText: text };
192
208
  return this;
193
209
  }
210
+ /**
211
+ * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually
212
+ * exclusive with the other `near*` clauses.
213
+ *
214
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
215
+ */
194
216
  nearId(id) {
195
217
  if (this.#near !== void 0) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
196
218
  this.#near = { id };
197
219
  return this;
198
220
  }
221
+ /**
222
+ * Declare which fields each match projects (id / vector / document / metadata). Required before a
223
+ * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples,
224
+ * or `{ field: config }` maps.
225
+ */
199
226
  select(...args) {
200
227
  this.#selectCalled = true;
201
228
  for (const arg of args) if (typeof arg === "string") {
@@ -223,10 +250,12 @@ var VectorQueryBuilder = class extends FilterBuilder {
223
250
  }
224
251
  return this;
225
252
  }
253
+ /** Cap the number of matches returned (the search `topK`). */
226
254
  limit(n) {
227
255
  this.#topK = n;
228
256
  return this;
229
257
  }
258
+ /** Skip the first `n` matches before returning results. */
230
259
  offset(n) {
231
260
  this.#offset = n;
232
261
  return this;
@@ -259,6 +288,7 @@ var VectorQueryBuilder = class extends FilterBuilder {
259
288
  this.#validateRawFilters(plan.filter);
260
289
  return await this.#sink.executeSearch(plan);
261
290
  }
291
+ /** Terminal: insert or replace `records` in the collection. */
262
292
  async upsert(records) {
263
293
  const plan = {
264
294
  collection: this.#collection,
@@ -267,6 +297,7 @@ var VectorQueryBuilder = class extends FilterBuilder {
267
297
  };
268
298
  await this.#sink.executeUpsert(plan);
269
299
  }
300
+ /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */
270
301
  async delete() {
271
302
  const ids = this.extractIdsFromFilter();
272
303
  const filter = this.buildFilter();
@@ -1 +1 @@
1
- {"version":3,"file":"builder.cjs","names":["#pushOrBranch","#sink","#collection","#topK","#near","#selectCalled","#projection","#offset","#consistency","#run","#validateRawFilters"],"sources":["../../../src/batteries/vector/builder.ts"],"sourcesContent":["/**\n * Knex-style chainable query builder for the vector storage battery.\n *\n * @module @nhtio/adk/batteries/vector/builder\n */\n\nimport { isRawFilter, isFilterCondition } from './filters'\nimport {\n E_VECTOR_STORE_QUERY_CONFLICT,\n E_VECTOR_STORE_PROJECTION_REQUIRED,\n E_VECTOR_STORE_RAW_BINDING_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\n} from './exceptions'\nimport type { VectorRecord, VectorMatch, VectorConsistency } from './types'\nimport type { SearchPlan, UpsertPlan, DeletePlan, Projection } from './plan'\nimport type { VectorFilter, FilterCondition, FilterOperator } from './filters'\n\nconst OP_ALIASES: Record<string, FilterOperator> = {\n '=': 'eq',\n '==': 'eq',\n '===': 'eq',\n '!=': 'ne',\n '<>': 'ne',\n '!==': 'ne',\n '>': 'gt',\n '>=': 'gte',\n '<': 'lt',\n '<=': 'lte',\n 'eq': 'eq',\n 'ne': 'ne',\n 'gt': 'gt',\n 'gte': 'gte',\n 'lt': 'lt',\n 'lte': 'lte',\n 'in': 'in',\n 'nin': 'nin',\n 'exists': 'exists',\n 'contains': 'contains',\n}\nconst normalizeOp = (op: string): FilterOperator => {\n const norm = OP_ALIASES[op]\n if (!norm) throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['builder', op])\n return norm\n}\n\nexport interface PlanSink {\n executeSearch(plan: SearchPlan): Promise<VectorMatch[]>\n executeUpsert(plan: UpsertPlan): Promise<void>\n executeDelete(plan: DeletePlan): Promise<void>\n}\n\nexport type SelectArg =\n | string\n | [string, Record<string, unknown>]\n | Record<string, Record<string, unknown> | true>\n\n/**\n * A callback that receives a fresh filter-only builder, used to express a parenthesized group of\n * conditions — `A AND (B OR C)`, `NOT (…)`, and arbitrary nesting. The callback mutates the builder\n * in place (knex-style); its accumulated conditions become a single nested `VectorFilter`.\n *\n * @see {@link FilterBuilder.where}\n */\nexport type FilterCallback = (qb: FilterBuilder) => void\n\n/**\n * The where-clause surface of the query builder, factored out so a grouping callback can be handed\n * a builder that only exposes filter methods (not `near*`/`select`/`limit` or the terminals).\n *\n * Chained `.where()` ANDs; the first `.orWhere()` snapshots the accumulated AND-list into the first\n * branch of an OR (knex semantics). Any of the where-methods also accepts a {@link FilterCallback}\n * to open a nested group, letting AND and OR mix to any depth.\n */\nclass FilterBuilder {\n protected andConditions: VectorFilter[] = []\n protected orBranches: VectorFilter[][] = []\n\n /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */\n protected runGroup(cb: FilterCallback): VectorFilter | undefined {\n const fb = new FilterBuilder()\n cb(fb)\n return fb.buildFilter()\n }\n\n where(cb: FilterCallback): this\n where(a: string, b?: unknown, c?: unknown): this\n where(obj: Record<string, unknown>): this\n where(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof a === 'function') {\n const group = this.runGroup(a)\n if (group !== undefined) {\n this.andConditions.push(group)\n }\n return this\n }\n if (typeof a === 'object' && !Array.isArray(a)) {\n for (const key of Object.keys(a)) {\n this.andConditions.push({\n field: key,\n op: 'eq',\n value: a[key] as FilterCondition['value'],\n })\n }\n return this\n }\n const field = a as string\n const value = b !== undefined ? (c !== undefined ? c : b) : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.andConditions.push({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n andWhere(cb: FilterCallback): this\n andWhere(a: string, b?: unknown, c?: unknown): this\n andWhere(obj: Record<string, unknown>): this\n andWhere(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n return this.where(a as any, b, c)\n }\n\n /**\n * Open a new OR branch holding a single filter. The accumulated AND-list is contributed as the\n * first OR-group by {@link buildFilter}, so each branch carries only its own condition(s) — that\n * is what makes `where(A).where(B).orWhere(C)` resolve to `(A AND B) OR C`.\n */\n #pushOrBranch(filter: VectorFilter): void {\n this.orBranches.push([filter])\n }\n\n orWhere(cb: FilterCallback): this\n orWhere(field: string, value: unknown): this\n orWhere(field: string, op: FilterOperator, value: unknown): this\n orWhere(field: string | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch(group)\n }\n return this\n }\n const value = c !== undefined ? c : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.#pushOrBranch({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n whereNot(cb: FilterCallback): this\n whereNot(field: string, value: unknown): this\n whereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.andConditions.push({ not: group })\n }\n return this\n }\n return this.where(field, 'ne', value as FilterCondition['value'])\n }\n\n orWhereNot(cb: FilterCallback): this\n orWhereNot(field: string, value: unknown): this\n orWhereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch({ not: group })\n }\n return this\n }\n return this.orWhere(field, 'ne', value)\n }\n\n whereIn(field: string, values: unknown[]): this {\n return this.where(field, 'in', values as FilterCondition['value'])\n }\n\n whereNotIn(field: string, values: unknown[]): this {\n return this.where(field, 'nin', values as FilterCondition['value'])\n }\n\n whereNull(field: string): this {\n return this.where(field, 'exists', false as FilterCondition['value'])\n }\n\n whereExists(field: string): this {\n return this.where(field, 'exists', true as FilterCondition['value'])\n }\n\n whereRaw(sql: string, bindings?: unknown[]): this\n whereRaw(rawObj: { $dialect: string; $raw: unknown; $bindings?: unknown[] }): this\n whereRaw(\n sqlOrObj: string | { $dialect: string; $raw: unknown; $bindings?: unknown[] },\n bindings?: unknown[]\n ): this {\n if (typeof sqlOrObj === 'object') {\n this.andConditions.push({\n $dialect: sqlOrObj.$dialect,\n $raw: sqlOrObj.$raw,\n $bindings: sqlOrObj.$bindings ?? [],\n })\n } else {\n this.andConditions.push({ $dialect: 'sql', $raw: sqlOrObj, $bindings: bindings ?? [] })\n }\n return this\n }\n\n protected buildFilter(): VectorFilter | undefined {\n if (this.andConditions.length === 0 && this.orBranches.length === 0) {\n return undefined\n }\n\n if (this.orBranches.length > 0) {\n const orGroups: VectorFilter[][] = []\n if (this.andConditions.length > 0) {\n orGroups.push(this.andConditions)\n }\n for (const branch of this.orBranches) {\n if (branch.length > 0) {\n orGroups.push(branch)\n }\n }\n if (orGroups.length === 1) {\n return { and: orGroups[0] }\n }\n return { or: orGroups.map((conds) => ({ and: conds })) }\n }\n\n return { and: this.andConditions }\n }\n\n protected extractIdsFromFilter(): string[] {\n const ids: string[] = []\n const only = this.andConditions.length === 1 ? this.andConditions[0] : undefined\n if (\n only &&\n isFilterCondition(only) &&\n only.field === 'id' &&\n only.op === 'in' &&\n Array.isArray(only.value)\n ) {\n ids.push(...(only.value as string[]))\n }\n return ids\n }\n}\n\nclass VectorQueryBuilder extends FilterBuilder implements PromiseLike<VectorMatch[]> {\n #sink: PlanSink\n #collection: string\n #near: { vector: number[] } | { serverText: string } | { id: string } | undefined\n #projection: Projection = { id: false, vector: false, document: false, metadata: false }\n #topK: number\n #offset: number = 0\n #selectCalled: boolean = false\n #consistency: VectorConsistency | undefined\n\n constructor(sink: PlanSink, collection: string, defaultTopK: number) {\n super()\n this.#sink = sink\n this.#collection = collection\n this.#topK = defaultTopK\n }\n\n nearVector(vector: number[]): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { vector }\n return this\n }\n\n nearText(text: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { serverText: text }\n return this\n }\n\n nearId(id: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { id }\n return this\n }\n\n select(...args: SelectArg[]): this {\n this.#selectCalled = true\n for (const arg of args) {\n if (typeof arg === 'string') {\n if (arg === '*') {\n this.#projection = { id: true, vector: {}, document: {}, metadata: {} }\n } else {\n if (arg === 'id') {\n this.#projection.id = true\n } else if (arg === 'vector') {\n this.#projection.vector = {}\n } else if (arg === 'document') {\n this.#projection.document = {}\n } else if (arg === 'metadata') {\n this.#projection.metadata = {}\n }\n }\n } else if (Array.isArray(arg)) {\n const [field, config] = arg\n if (field === 'vector') {\n this.#projection.vector = config as { name?: string }\n } else if (field === 'document') {\n this.#projection.document = config as { field?: string }\n } else if (field === 'metadata') {\n this.#projection.metadata = config as { fields?: string[] }\n } else if (field === 'id') {\n this.#projection.id = true\n }\n } else if (typeof arg === 'object') {\n for (const key of Object.keys(arg)) {\n if (key === 'vector') {\n this.#projection.vector = arg[key] as { name?: string }\n } else if (key === 'document') {\n this.#projection.document = arg[key] as { field?: string }\n } else if (key === 'metadata') {\n this.#projection.metadata = arg[key] as { fields?: string[] }\n } else if (key === 'id') {\n this.#projection.id = true\n }\n }\n }\n }\n return this\n }\n\n limit(n: number): this {\n this.#topK = n\n return this\n }\n\n offset(n: number): this {\n this.#offset = n\n return this\n }\n\n /**\n * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`.\n * Universal across adapters: strongly-consistent backends ignore it (no-op), so a chain\n * written for an eventually-consistent backend keeps working verbatim when the adapter is\n * swapped. Precedence: this > the store's `consistency` option > the adapter's declared\n * `capabilities.consistency.default`. See {@link VectorConsistency}.\n */\n consistency(mode: VectorConsistency): this {\n this.#consistency = mode\n return this\n }\n\n then<TR1 = VectorMatch[], TR2 = never>(\n onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike<TR1>) | null,\n onrejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null\n ): PromiseLike<TR1 | TR2> {\n return this.#run().then(onfulfilled as any, onrejected as any)\n }\n\n async #run(): Promise<VectorMatch[]> {\n if (!this.#selectCalled) {\n throw new E_VECTOR_STORE_PROJECTION_REQUIRED()\n }\n\n const filter = this.buildFilter()\n\n const plan: SearchPlan = {\n collection: this.#collection,\n near: this.#near,\n filter,\n topK: this.#topK,\n offset: this.#offset,\n projection: this.#projection,\n }\n\n this.#validateRawFilters(plan.filter)\n\n return await this.#sink.executeSearch(plan)\n }\n\n async upsert(records: VectorRecord[]): Promise<void> {\n const plan: UpsertPlan = {\n collection: this.#collection,\n records,\n consistency: this.#consistency,\n }\n await this.#sink.executeUpsert(plan)\n }\n\n async delete(): Promise<void> {\n const ids = this.extractIdsFromFilter()\n const filter = this.buildFilter()\n\n const plan: DeletePlan = {\n collection: this.#collection,\n ids: ids.length > 0 ? ids : undefined,\n filter: filter && Object.keys(filter).length > 0 ? filter : undefined,\n consistency: this.#consistency,\n }\n\n await this.#sink.executeDelete(plan)\n }\n\n #validateRawFilters(filter: VectorFilter | undefined): void {\n if (!filter) {\n return\n }\n\n if (isRawFilter(filter)) {\n const raw = filter.$raw as string\n const placeholders = (raw.match(/\\?/g) || []).length\n if (placeholders !== filter.$bindings?.length) {\n throw new E_VECTOR_STORE_RAW_BINDING_MISMATCH([placeholders, filter.$bindings?.length ?? 0])\n }\n return\n }\n\n if ('and' in filter && filter.and) {\n for (const f of filter.and) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('or' in filter && filter.or) {\n for (const f of filter.or) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('not' in filter && filter.not) {\n this.#validateRawFilters(filter.not)\n }\n }\n}\n\nexport { VectorQueryBuilder, FilterBuilder }\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.cjs","names":["#pushOrBranch","#sink","#collection","#topK","#near","#selectCalled","#projection","#offset","#consistency","#run","#validateRawFilters"],"sources":["../../../src/batteries/vector/builder.ts"],"sourcesContent":["/**\n * Knex-style chainable query builder for the vector storage battery.\n *\n * @module @nhtio/adk/batteries/vector/builder\n */\n\nimport { isRawFilter, isFilterCondition } from './filters'\nimport {\n E_VECTOR_STORE_QUERY_CONFLICT,\n E_VECTOR_STORE_PROJECTION_REQUIRED,\n E_VECTOR_STORE_RAW_BINDING_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\n} from './exceptions'\nimport type { VectorRecord, VectorMatch, VectorConsistency } from './types'\nimport type { SearchPlan, UpsertPlan, DeletePlan, Projection } from './plan'\nimport type { VectorFilter, FilterCondition, FilterOperator } from './filters'\n\nconst OP_ALIASES: Record<string, FilterOperator> = {\n '=': 'eq',\n '==': 'eq',\n '===': 'eq',\n '!=': 'ne',\n '<>': 'ne',\n '!==': 'ne',\n '>': 'gt',\n '>=': 'gte',\n '<': 'lt',\n '<=': 'lte',\n 'eq': 'eq',\n 'ne': 'ne',\n 'gt': 'gt',\n 'gte': 'gte',\n 'lt': 'lt',\n 'lte': 'lte',\n 'in': 'in',\n 'nin': 'nin',\n 'exists': 'exists',\n 'contains': 'contains',\n}\nconst normalizeOp = (op: string): FilterOperator => {\n const norm = OP_ALIASES[op]\n if (!norm) throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['builder', op])\n return norm\n}\n\n/**\n * The execution backend a {@link VectorQueryBuilder} drains its assembled plans into. Implemented\n * by the vector store; the builder produces {@link SearchPlan}/{@link UpsertPlan}/{@link DeletePlan}\n * objects and hands them here rather than touching the adapter directly.\n */\nexport interface PlanSink {\n /** Executes an assembled search plan and resolves the matching records. */\n executeSearch(plan: SearchPlan): Promise<VectorMatch[]>\n /** Executes an assembled upsert plan. */\n executeUpsert(plan: UpsertPlan): Promise<void>\n /** Executes an assembled delete plan. */\n executeDelete(plan: DeletePlan): Promise<void>\n}\n\n/**\n * An argument accepted by {@link VectorQueryBuilder.select} — a field name (or `'*'`), a\n * `[field, config]` tuple, or a `{ field: config }` map selecting and configuring projected fields.\n */\nexport type SelectArg =\n | string\n | [string, Record<string, unknown>]\n | Record<string, Record<string, unknown> | true>\n\n/**\n * A callback that receives a fresh filter-only builder, used to express a parenthesized group of\n * conditions — `A AND (B OR C)`, `NOT (…)`, and arbitrary nesting. The callback mutates the builder\n * in place (knex-style); its accumulated conditions become a single nested `VectorFilter`.\n *\n * @see {@link FilterBuilder.where}\n */\nexport type FilterCallback = (qb: FilterBuilder) => void\n\n/**\n * The where-clause surface of the query builder, factored out so a grouping callback can be handed\n * a builder that only exposes filter methods (not `near*`/`select`/`limit` or the terminals).\n *\n * Chained `.where()` ANDs; the first `.orWhere()` snapshots the accumulated AND-list into the first\n * branch of an OR (knex semantics). Any of the where-methods also accepts a {@link FilterCallback}\n * to open a nested group, letting AND and OR mix to any depth.\n */\nclass FilterBuilder {\n protected andConditions: VectorFilter[] = []\n protected orBranches: VectorFilter[][] = []\n\n /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */\n protected runGroup(cb: FilterCallback): VectorFilter | undefined {\n const fb = new FilterBuilder()\n cb(fb)\n return fb.buildFilter()\n }\n\n /** Add a parenthesized condition group via a {@link FilterCallback}; ANDed with prior conditions. */\n where(cb: FilterCallback): this\n /** Add a condition `field op value` (or `field = value` when `c` is omitted); ANDed with prior conditions. */\n where(a: string, b?: unknown, c?: unknown): this\n /** Add equality conditions for each key of `obj`; ANDed with prior conditions. */\n where(obj: Record<string, unknown>): this\n where(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof a === 'function') {\n const group = this.runGroup(a)\n if (group !== undefined) {\n this.andConditions.push(group)\n }\n return this\n }\n if (typeof a === 'object' && !Array.isArray(a)) {\n for (const key of Object.keys(a)) {\n this.andConditions.push({\n field: key,\n op: 'eq',\n value: a[key] as FilterCondition['value'],\n })\n }\n return this\n }\n const field = a as string\n const value = b !== undefined ? (c !== undefined ? c : b) : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.andConditions.push({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n /** Alias of {@link FilterBuilder.where} (callback group form) for readability in a chain. */\n andWhere(cb: FilterCallback): this\n /** Alias of {@link FilterBuilder.where} (`field op value` form) for readability in a chain. */\n andWhere(a: string, b?: unknown, c?: unknown): this\n /** Alias of {@link FilterBuilder.where} (object form) for readability in a chain. */\n andWhere(obj: Record<string, unknown>): this\n andWhere(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n return this.where(a as any, b, c)\n }\n\n /**\n * Open a new OR branch holding a single filter. The accumulated AND-list is contributed as the\n * first OR-group by {@link buildFilter}, so each branch carries only its own condition(s) — that\n * is what makes `where(A).where(B).orWhere(C)` resolve to `(A AND B) OR C`.\n */\n #pushOrBranch(filter: VectorFilter): void {\n this.orBranches.push([filter])\n }\n\n /** Open a new OR branch holding a parenthesized condition group via a {@link FilterCallback}. */\n orWhere(cb: FilterCallback): this\n /** Open a new OR branch holding the equality condition `field = value`. */\n orWhere(field: string, value: unknown): this\n /** Open a new OR branch holding the condition `field op value`. */\n orWhere(field: string, op: FilterOperator, value: unknown): this\n orWhere(field: string | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch(group)\n }\n return this\n }\n const value = c !== undefined ? c : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.#pushOrBranch({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n /** AND a negated parenthesized condition group via a {@link FilterCallback}. */\n whereNot(cb: FilterCallback): this\n /** AND the negated equality condition `field != value`. */\n whereNot(field: string, value: unknown): this\n whereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.andConditions.push({ not: group })\n }\n return this\n }\n return this.where(field, 'ne', value as FilterCondition['value'])\n }\n\n /** Open a new OR branch holding a negated parenthesized condition group via a {@link FilterCallback}. */\n orWhereNot(cb: FilterCallback): this\n /** Open a new OR branch holding the negated equality condition `field != value`. */\n orWhereNot(field: string, value: unknown): this\n orWhereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch({ not: group })\n }\n return this\n }\n return this.orWhere(field, 'ne', value)\n }\n\n /** AND the condition that `field`'s value is one of `values`. */\n whereIn(field: string, values: unknown[]): this {\n return this.where(field, 'in', values as FilterCondition['value'])\n }\n\n /** AND the condition that `field`'s value is none of `values`. */\n whereNotIn(field: string, values: unknown[]): this {\n return this.where(field, 'nin', values as FilterCondition['value'])\n }\n\n /** AND the condition that `field` is absent (does not exist). */\n whereNull(field: string): this {\n return this.where(field, 'exists', false as FilterCondition['value'])\n }\n\n /** AND the condition that `field` is present (exists). */\n whereExists(field: string): this {\n return this.where(field, 'exists', true as FilterCondition['value'])\n }\n\n /** AND a raw, adapter-dialect filter expressed as SQL text plus positional `bindings`. */\n whereRaw(sql: string, bindings?: unknown[]): this\n /** AND a raw, adapter-dialect filter expressed as a `{ $dialect, $raw, $bindings }` object. */\n whereRaw(rawObj: { $dialect: string; $raw: unknown; $bindings?: unknown[] }): this\n whereRaw(\n sqlOrObj: string | { $dialect: string; $raw: unknown; $bindings?: unknown[] },\n bindings?: unknown[]\n ): this {\n if (typeof sqlOrObj === 'object') {\n this.andConditions.push({\n $dialect: sqlOrObj.$dialect,\n $raw: sqlOrObj.$raw,\n $bindings: sqlOrObj.$bindings ?? [],\n })\n } else {\n this.andConditions.push({ $dialect: 'sql', $raw: sqlOrObj, $bindings: bindings ?? [] })\n }\n return this\n }\n\n protected buildFilter(): VectorFilter | undefined {\n if (this.andConditions.length === 0 && this.orBranches.length === 0) {\n return undefined\n }\n\n if (this.orBranches.length > 0) {\n const orGroups: VectorFilter[][] = []\n if (this.andConditions.length > 0) {\n orGroups.push(this.andConditions)\n }\n for (const branch of this.orBranches) {\n if (branch.length > 0) {\n orGroups.push(branch)\n }\n }\n if (orGroups.length === 1) {\n return { and: orGroups[0] }\n }\n return { or: orGroups.map((conds) => ({ and: conds })) }\n }\n\n return { and: this.andConditions }\n }\n\n protected extractIdsFromFilter(): string[] {\n const ids: string[] = []\n const only = this.andConditions.length === 1 ? this.andConditions[0] : undefined\n if (\n only &&\n isFilterCondition(only) &&\n only.field === 'id' &&\n only.op === 'in' &&\n Array.isArray(only.value)\n ) {\n ids.push(...(only.value as string[]))\n }\n return ids\n }\n}\n\nclass VectorQueryBuilder extends FilterBuilder implements PromiseLike<VectorMatch[]> {\n #sink: PlanSink\n #collection: string\n #near: { vector: number[] } | { serverText: string } | { id: string } | undefined\n #projection: Projection = { id: false, vector: false, document: false, metadata: false }\n #topK: number\n #offset: number = 0\n #selectCalled: boolean = false\n #consistency: VectorConsistency | undefined\n\n constructor(sink: PlanSink, collection: string, defaultTopK: number) {\n super()\n this.#sink = sink\n this.#collection = collection\n this.#topK = defaultTopK\n }\n\n /**\n * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the\n * other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearVector(vector: number[]): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { vector }\n return this\n }\n\n /**\n * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive\n * with the other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearText(text: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { serverText: text }\n return this\n }\n\n /**\n * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually\n * exclusive with the other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearId(id: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { id }\n return this\n }\n\n /**\n * Declare which fields each match projects (id / vector / document / metadata). Required before a\n * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples,\n * or `{ field: config }` maps.\n */\n select(...args: SelectArg[]): this {\n this.#selectCalled = true\n for (const arg of args) {\n if (typeof arg === 'string') {\n if (arg === '*') {\n this.#projection = { id: true, vector: {}, document: {}, metadata: {} }\n } else {\n if (arg === 'id') {\n this.#projection.id = true\n } else if (arg === 'vector') {\n this.#projection.vector = {}\n } else if (arg === 'document') {\n this.#projection.document = {}\n } else if (arg === 'metadata') {\n this.#projection.metadata = {}\n }\n }\n } else if (Array.isArray(arg)) {\n const [field, config] = arg\n if (field === 'vector') {\n this.#projection.vector = config as { name?: string }\n } else if (field === 'document') {\n this.#projection.document = config as { field?: string }\n } else if (field === 'metadata') {\n this.#projection.metadata = config as { fields?: string[] }\n } else if (field === 'id') {\n this.#projection.id = true\n }\n } else if (typeof arg === 'object') {\n for (const key of Object.keys(arg)) {\n if (key === 'vector') {\n this.#projection.vector = arg[key] as { name?: string }\n } else if (key === 'document') {\n this.#projection.document = arg[key] as { field?: string }\n } else if (key === 'metadata') {\n this.#projection.metadata = arg[key] as { fields?: string[] }\n } else if (key === 'id') {\n this.#projection.id = true\n }\n }\n }\n }\n return this\n }\n\n /** Cap the number of matches returned (the search `topK`). */\n limit(n: number): this {\n this.#topK = n\n return this\n }\n\n /** Skip the first `n` matches before returning results. */\n offset(n: number): this {\n this.#offset = n\n return this\n }\n\n /**\n * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`.\n * Universal across adapters: strongly-consistent backends ignore it (no-op), so a chain\n * written for an eventually-consistent backend keeps working verbatim when the adapter is\n * swapped. Precedence: this > the store's `consistency` option > the adapter's declared\n * `capabilities.consistency.default`. See {@link VectorConsistency}.\n */\n consistency(mode: VectorConsistency): this {\n this.#consistency = mode\n return this\n }\n\n then<TR1 = VectorMatch[], TR2 = never>(\n onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike<TR1>) | null,\n onrejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null\n ): PromiseLike<TR1 | TR2> {\n return this.#run().then(onfulfilled as any, onrejected as any)\n }\n\n async #run(): Promise<VectorMatch[]> {\n if (!this.#selectCalled) {\n throw new E_VECTOR_STORE_PROJECTION_REQUIRED()\n }\n\n const filter = this.buildFilter()\n\n const plan: SearchPlan = {\n collection: this.#collection,\n near: this.#near,\n filter,\n topK: this.#topK,\n offset: this.#offset,\n projection: this.#projection,\n }\n\n this.#validateRawFilters(plan.filter)\n\n return await this.#sink.executeSearch(plan)\n }\n\n /** Terminal: insert or replace `records` in the collection. */\n async upsert(records: VectorRecord[]): Promise<void> {\n const plan: UpsertPlan = {\n collection: this.#collection,\n records,\n consistency: this.#consistency,\n }\n await this.#sink.executeUpsert(plan)\n }\n\n /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */\n async delete(): Promise<void> {\n const ids = this.extractIdsFromFilter()\n const filter = this.buildFilter()\n\n const plan: DeletePlan = {\n collection: this.#collection,\n ids: ids.length > 0 ? ids : undefined,\n filter: filter && Object.keys(filter).length > 0 ? filter : undefined,\n consistency: this.#consistency,\n }\n\n await this.#sink.executeDelete(plan)\n }\n\n #validateRawFilters(filter: VectorFilter | undefined): void {\n if (!filter) {\n return\n }\n\n if (isRawFilter(filter)) {\n const raw = filter.$raw as string\n const placeholders = (raw.match(/\\?/g) || []).length\n if (placeholders !== filter.$bindings?.length) {\n throw new E_VECTOR_STORE_RAW_BINDING_MISMATCH([placeholders, filter.$bindings?.length ?? 0])\n }\n return\n }\n\n if ('and' in filter && filter.and) {\n for (const f of filter.and) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('or' in filter && filter.or) {\n for (const f of filter.or) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('not' in filter && filter.not) {\n this.#validateRawFilters(filter.not)\n }\n }\n}\n\nexport { VectorQueryBuilder, FilterBuilder }\n"],"mappings":"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"}
@@ -6,11 +6,23 @@
6
6
  import type { VectorRecord, VectorMatch, VectorConsistency } from "./types";
7
7
  import type { SearchPlan, UpsertPlan, DeletePlan } from "./plan";
8
8
  import type { VectorFilter, FilterOperator } from "./filters";
9
+ /**
10
+ * The execution backend a {@link VectorQueryBuilder} drains its assembled plans into. Implemented
11
+ * by the vector store; the builder produces {@link SearchPlan}/{@link UpsertPlan}/{@link DeletePlan}
12
+ * objects and hands them here rather than touching the adapter directly.
13
+ */
9
14
  export interface PlanSink {
15
+ /** Executes an assembled search plan and resolves the matching records. */
10
16
  executeSearch(plan: SearchPlan): Promise<VectorMatch[]>;
17
+ /** Executes an assembled upsert plan. */
11
18
  executeUpsert(plan: UpsertPlan): Promise<void>;
19
+ /** Executes an assembled delete plan. */
12
20
  executeDelete(plan: DeletePlan): Promise<void>;
13
21
  }
22
+ /**
23
+ * An argument accepted by {@link VectorQueryBuilder.select} — a field name (or `'*'`), a
24
+ * `[field, config]` tuple, or a `{ field: config }` map selecting and configuring projected fields.
25
+ */
14
26
  export type SelectArg = string | [
15
27
  string,
16
28
  Record<string, unknown>
@@ -37,24 +49,43 @@ declare class FilterBuilder {
37
49
  protected orBranches: VectorFilter[][];
38
50
  /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */
39
51
  protected runGroup(cb: FilterCallback): VectorFilter | undefined;
52
+ /** Add a parenthesized condition group via a {@link FilterCallback}; ANDed with prior conditions. */
40
53
  where(cb: FilterCallback): this;
54
+ /** Add a condition `field op value` (or `field = value` when `c` is omitted); ANDed with prior conditions. */
41
55
  where(a: string, b?: unknown, c?: unknown): this;
56
+ /** Add equality conditions for each key of `obj`; ANDed with prior conditions. */
42
57
  where(obj: Record<string, unknown>): this;
58
+ /** Alias of {@link FilterBuilder.where} (callback group form) for readability in a chain. */
43
59
  andWhere(cb: FilterCallback): this;
60
+ /** Alias of {@link FilterBuilder.where} (`field op value` form) for readability in a chain. */
44
61
  andWhere(a: string, b?: unknown, c?: unknown): this;
62
+ /** Alias of {@link FilterBuilder.where} (object form) for readability in a chain. */
45
63
  andWhere(obj: Record<string, unknown>): this;
64
+ /** Open a new OR branch holding a parenthesized condition group via a {@link FilterCallback}. */
46
65
  orWhere(cb: FilterCallback): this;
66
+ /** Open a new OR branch holding the equality condition `field = value`. */
47
67
  orWhere(field: string, value: unknown): this;
68
+ /** Open a new OR branch holding the condition `field op value`. */
48
69
  orWhere(field: string, op: FilterOperator, value: unknown): this;
70
+ /** AND a negated parenthesized condition group via a {@link FilterCallback}. */
49
71
  whereNot(cb: FilterCallback): this;
72
+ /** AND the negated equality condition `field != value`. */
50
73
  whereNot(field: string, value: unknown): this;
74
+ /** Open a new OR branch holding a negated parenthesized condition group via a {@link FilterCallback}. */
51
75
  orWhereNot(cb: FilterCallback): this;
76
+ /** Open a new OR branch holding the negated equality condition `field != value`. */
52
77
  orWhereNot(field: string, value: unknown): this;
78
+ /** AND the condition that `field`'s value is one of `values`. */
53
79
  whereIn(field: string, values: unknown[]): this;
80
+ /** AND the condition that `field`'s value is none of `values`. */
54
81
  whereNotIn(field: string, values: unknown[]): this;
82
+ /** AND the condition that `field` is absent (does not exist). */
55
83
  whereNull(field: string): this;
84
+ /** AND the condition that `field` is present (exists). */
56
85
  whereExists(field: string): this;
86
+ /** AND a raw, adapter-dialect filter expressed as SQL text plus positional `bindings`. */
57
87
  whereRaw(sql: string, bindings?: unknown[]): this;
88
+ /** AND a raw, adapter-dialect filter expressed as a `{ $dialect, $raw, $bindings }` object. */
58
89
  whereRaw(rawObj: {
59
90
  $dialect: string;
60
91
  $raw: unknown;
@@ -66,11 +97,36 @@ declare class FilterBuilder {
66
97
  declare class VectorQueryBuilder extends FilterBuilder implements PromiseLike<VectorMatch[]> {
67
98
  #private;
68
99
  constructor(sink: PlanSink, collection: string, defaultTopK: number);
100
+ /**
101
+ * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the
102
+ * other `near*` clauses.
103
+ *
104
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
105
+ */
69
106
  nearVector(vector: number[]): this;
107
+ /**
108
+ * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive
109
+ * with the other `near*` clauses.
110
+ *
111
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
112
+ */
70
113
  nearText(text: string): this;
114
+ /**
115
+ * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually
116
+ * exclusive with the other `near*` clauses.
117
+ *
118
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
119
+ */
71
120
  nearId(id: string): this;
121
+ /**
122
+ * Declare which fields each match projects (id / vector / document / metadata). Required before a
123
+ * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples,
124
+ * or `{ field: config }` maps.
125
+ */
72
126
  select(...args: SelectArg[]): this;
127
+ /** Cap the number of matches returned (the search `topK`). */
73
128
  limit(n: number): this;
129
+ /** Skip the first `n` matches before returning results. */
74
130
  offset(n: number): this;
75
131
  /**
76
132
  * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`.
@@ -81,7 +137,9 @@ declare class VectorQueryBuilder extends FilterBuilder implements PromiseLike<Ve
81
137
  */
82
138
  consistency(mode: VectorConsistency): this;
83
139
  then<TR1 = VectorMatch[], TR2 = never>(onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike<TR1>) | null, onrejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null): PromiseLike<TR1 | TR2>;
140
+ /** Terminal: insert or replace `records` in the collection. */
84
141
  upsert(records: VectorRecord[]): Promise<void>;
142
+ /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */
85
143
  delete(): Promise<void>;
86
144
  }
87
145
  export { VectorQueryBuilder, FilterBuilder };
@@ -116,15 +116,19 @@ var FilterBuilder = class FilterBuilder {
116
116
  }
117
117
  return this.orWhere(field, "ne", value);
118
118
  }
119
+ /** AND the condition that `field`'s value is one of `values`. */
119
120
  whereIn(field, values) {
120
121
  return this.where(field, "in", values);
121
122
  }
123
+ /** AND the condition that `field`'s value is none of `values`. */
122
124
  whereNotIn(field, values) {
123
125
  return this.where(field, "nin", values);
124
126
  }
127
+ /** AND the condition that `field` is absent (does not exist). */
125
128
  whereNull(field) {
126
129
  return this.where(field, "exists", false);
127
130
  }
131
+ /** AND the condition that `field` is present (exists). */
128
132
  whereExists(field) {
129
133
  return this.where(field, "exists", true);
130
134
  }
@@ -179,21 +183,44 @@ var VectorQueryBuilder = class extends FilterBuilder {
179
183
  this.#collection = collection;
180
184
  this.#topK = defaultTopK;
181
185
  }
186
+ /**
187
+ * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the
188
+ * other `near*` clauses.
189
+ *
190
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
191
+ */
182
192
  nearVector(vector) {
183
193
  if (this.#near !== void 0) throw new E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
184
194
  this.#near = { vector };
185
195
  return this;
186
196
  }
197
+ /**
198
+ * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive
199
+ * with the other `near*` clauses.
200
+ *
201
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
202
+ */
187
203
  nearText(text) {
188
204
  if (this.#near !== void 0) throw new E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
189
205
  this.#near = { serverText: text };
190
206
  return this;
191
207
  }
208
+ /**
209
+ * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually
210
+ * exclusive with the other `near*` clauses.
211
+ *
212
+ * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.
213
+ */
192
214
  nearId(id) {
193
215
  if (this.#near !== void 0) throw new E_VECTOR_STORE_QUERY_CONFLICT(["a near* clause was already set"]);
194
216
  this.#near = { id };
195
217
  return this;
196
218
  }
219
+ /**
220
+ * Declare which fields each match projects (id / vector / document / metadata). Required before a
221
+ * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples,
222
+ * or `{ field: config }` maps.
223
+ */
197
224
  select(...args) {
198
225
  this.#selectCalled = true;
199
226
  for (const arg of args) if (typeof arg === "string") {
@@ -221,10 +248,12 @@ var VectorQueryBuilder = class extends FilterBuilder {
221
248
  }
222
249
  return this;
223
250
  }
251
+ /** Cap the number of matches returned (the search `topK`). */
224
252
  limit(n) {
225
253
  this.#topK = n;
226
254
  return this;
227
255
  }
256
+ /** Skip the first `n` matches before returning results. */
228
257
  offset(n) {
229
258
  this.#offset = n;
230
259
  return this;
@@ -257,6 +286,7 @@ var VectorQueryBuilder = class extends FilterBuilder {
257
286
  this.#validateRawFilters(plan.filter);
258
287
  return await this.#sink.executeSearch(plan);
259
288
  }
289
+ /** Terminal: insert or replace `records` in the collection. */
260
290
  async upsert(records) {
261
291
  const plan = {
262
292
  collection: this.#collection,
@@ -265,6 +295,7 @@ var VectorQueryBuilder = class extends FilterBuilder {
265
295
  };
266
296
  await this.#sink.executeUpsert(plan);
267
297
  }
298
+ /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */
268
299
  async delete() {
269
300
  const ids = this.extractIdsFromFilter();
270
301
  const filter = this.buildFilter();
@@ -1 +1 @@
1
- {"version":3,"file":"builder.mjs","names":["#pushOrBranch","#sink","#collection","#topK","#near","#selectCalled","#projection","#offset","#consistency","#run","#validateRawFilters"],"sources":["../../../src/batteries/vector/builder.ts"],"sourcesContent":["/**\n * Knex-style chainable query builder for the vector storage battery.\n *\n * @module @nhtio/adk/batteries/vector/builder\n */\n\nimport { isRawFilter, isFilterCondition } from './filters'\nimport {\n E_VECTOR_STORE_QUERY_CONFLICT,\n E_VECTOR_STORE_PROJECTION_REQUIRED,\n E_VECTOR_STORE_RAW_BINDING_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\n} from './exceptions'\nimport type { VectorRecord, VectorMatch, VectorConsistency } from './types'\nimport type { SearchPlan, UpsertPlan, DeletePlan, Projection } from './plan'\nimport type { VectorFilter, FilterCondition, FilterOperator } from './filters'\n\nconst OP_ALIASES: Record<string, FilterOperator> = {\n '=': 'eq',\n '==': 'eq',\n '===': 'eq',\n '!=': 'ne',\n '<>': 'ne',\n '!==': 'ne',\n '>': 'gt',\n '>=': 'gte',\n '<': 'lt',\n '<=': 'lte',\n 'eq': 'eq',\n 'ne': 'ne',\n 'gt': 'gt',\n 'gte': 'gte',\n 'lt': 'lt',\n 'lte': 'lte',\n 'in': 'in',\n 'nin': 'nin',\n 'exists': 'exists',\n 'contains': 'contains',\n}\nconst normalizeOp = (op: string): FilterOperator => {\n const norm = OP_ALIASES[op]\n if (!norm) throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['builder', op])\n return norm\n}\n\nexport interface PlanSink {\n executeSearch(plan: SearchPlan): Promise<VectorMatch[]>\n executeUpsert(plan: UpsertPlan): Promise<void>\n executeDelete(plan: DeletePlan): Promise<void>\n}\n\nexport type SelectArg =\n | string\n | [string, Record<string, unknown>]\n | Record<string, Record<string, unknown> | true>\n\n/**\n * A callback that receives a fresh filter-only builder, used to express a parenthesized group of\n * conditions — `A AND (B OR C)`, `NOT (…)`, and arbitrary nesting. The callback mutates the builder\n * in place (knex-style); its accumulated conditions become a single nested `VectorFilter`.\n *\n * @see {@link FilterBuilder.where}\n */\nexport type FilterCallback = (qb: FilterBuilder) => void\n\n/**\n * The where-clause surface of the query builder, factored out so a grouping callback can be handed\n * a builder that only exposes filter methods (not `near*`/`select`/`limit` or the terminals).\n *\n * Chained `.where()` ANDs; the first `.orWhere()` snapshots the accumulated AND-list into the first\n * branch of an OR (knex semantics). Any of the where-methods also accepts a {@link FilterCallback}\n * to open a nested group, letting AND and OR mix to any depth.\n */\nclass FilterBuilder {\n protected andConditions: VectorFilter[] = []\n protected orBranches: VectorFilter[][] = []\n\n /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */\n protected runGroup(cb: FilterCallback): VectorFilter | undefined {\n const fb = new FilterBuilder()\n cb(fb)\n return fb.buildFilter()\n }\n\n where(cb: FilterCallback): this\n where(a: string, b?: unknown, c?: unknown): this\n where(obj: Record<string, unknown>): this\n where(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof a === 'function') {\n const group = this.runGroup(a)\n if (group !== undefined) {\n this.andConditions.push(group)\n }\n return this\n }\n if (typeof a === 'object' && !Array.isArray(a)) {\n for (const key of Object.keys(a)) {\n this.andConditions.push({\n field: key,\n op: 'eq',\n value: a[key] as FilterCondition['value'],\n })\n }\n return this\n }\n const field = a as string\n const value = b !== undefined ? (c !== undefined ? c : b) : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.andConditions.push({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n andWhere(cb: FilterCallback): this\n andWhere(a: string, b?: unknown, c?: unknown): this\n andWhere(obj: Record<string, unknown>): this\n andWhere(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n return this.where(a as any, b, c)\n }\n\n /**\n * Open a new OR branch holding a single filter. The accumulated AND-list is contributed as the\n * first OR-group by {@link buildFilter}, so each branch carries only its own condition(s) — that\n * is what makes `where(A).where(B).orWhere(C)` resolve to `(A AND B) OR C`.\n */\n #pushOrBranch(filter: VectorFilter): void {\n this.orBranches.push([filter])\n }\n\n orWhere(cb: FilterCallback): this\n orWhere(field: string, value: unknown): this\n orWhere(field: string, op: FilterOperator, value: unknown): this\n orWhere(field: string | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch(group)\n }\n return this\n }\n const value = c !== undefined ? c : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.#pushOrBranch({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n whereNot(cb: FilterCallback): this\n whereNot(field: string, value: unknown): this\n whereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.andConditions.push({ not: group })\n }\n return this\n }\n return this.where(field, 'ne', value as FilterCondition['value'])\n }\n\n orWhereNot(cb: FilterCallback): this\n orWhereNot(field: string, value: unknown): this\n orWhereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch({ not: group })\n }\n return this\n }\n return this.orWhere(field, 'ne', value)\n }\n\n whereIn(field: string, values: unknown[]): this {\n return this.where(field, 'in', values as FilterCondition['value'])\n }\n\n whereNotIn(field: string, values: unknown[]): this {\n return this.where(field, 'nin', values as FilterCondition['value'])\n }\n\n whereNull(field: string): this {\n return this.where(field, 'exists', false as FilterCondition['value'])\n }\n\n whereExists(field: string): this {\n return this.where(field, 'exists', true as FilterCondition['value'])\n }\n\n whereRaw(sql: string, bindings?: unknown[]): this\n whereRaw(rawObj: { $dialect: string; $raw: unknown; $bindings?: unknown[] }): this\n whereRaw(\n sqlOrObj: string | { $dialect: string; $raw: unknown; $bindings?: unknown[] },\n bindings?: unknown[]\n ): this {\n if (typeof sqlOrObj === 'object') {\n this.andConditions.push({\n $dialect: sqlOrObj.$dialect,\n $raw: sqlOrObj.$raw,\n $bindings: sqlOrObj.$bindings ?? [],\n })\n } else {\n this.andConditions.push({ $dialect: 'sql', $raw: sqlOrObj, $bindings: bindings ?? [] })\n }\n return this\n }\n\n protected buildFilter(): VectorFilter | undefined {\n if (this.andConditions.length === 0 && this.orBranches.length === 0) {\n return undefined\n }\n\n if (this.orBranches.length > 0) {\n const orGroups: VectorFilter[][] = []\n if (this.andConditions.length > 0) {\n orGroups.push(this.andConditions)\n }\n for (const branch of this.orBranches) {\n if (branch.length > 0) {\n orGroups.push(branch)\n }\n }\n if (orGroups.length === 1) {\n return { and: orGroups[0] }\n }\n return { or: orGroups.map((conds) => ({ and: conds })) }\n }\n\n return { and: this.andConditions }\n }\n\n protected extractIdsFromFilter(): string[] {\n const ids: string[] = []\n const only = this.andConditions.length === 1 ? this.andConditions[0] : undefined\n if (\n only &&\n isFilterCondition(only) &&\n only.field === 'id' &&\n only.op === 'in' &&\n Array.isArray(only.value)\n ) {\n ids.push(...(only.value as string[]))\n }\n return ids\n }\n}\n\nclass VectorQueryBuilder extends FilterBuilder implements PromiseLike<VectorMatch[]> {\n #sink: PlanSink\n #collection: string\n #near: { vector: number[] } | { serverText: string } | { id: string } | undefined\n #projection: Projection = { id: false, vector: false, document: false, metadata: false }\n #topK: number\n #offset: number = 0\n #selectCalled: boolean = false\n #consistency: VectorConsistency | undefined\n\n constructor(sink: PlanSink, collection: string, defaultTopK: number) {\n super()\n this.#sink = sink\n this.#collection = collection\n this.#topK = defaultTopK\n }\n\n nearVector(vector: number[]): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { vector }\n return this\n }\n\n nearText(text: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { serverText: text }\n return this\n }\n\n nearId(id: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { id }\n return this\n }\n\n select(...args: SelectArg[]): this {\n this.#selectCalled = true\n for (const arg of args) {\n if (typeof arg === 'string') {\n if (arg === '*') {\n this.#projection = { id: true, vector: {}, document: {}, metadata: {} }\n } else {\n if (arg === 'id') {\n this.#projection.id = true\n } else if (arg === 'vector') {\n this.#projection.vector = {}\n } else if (arg === 'document') {\n this.#projection.document = {}\n } else if (arg === 'metadata') {\n this.#projection.metadata = {}\n }\n }\n } else if (Array.isArray(arg)) {\n const [field, config] = arg\n if (field === 'vector') {\n this.#projection.vector = config as { name?: string }\n } else if (field === 'document') {\n this.#projection.document = config as { field?: string }\n } else if (field === 'metadata') {\n this.#projection.metadata = config as { fields?: string[] }\n } else if (field === 'id') {\n this.#projection.id = true\n }\n } else if (typeof arg === 'object') {\n for (const key of Object.keys(arg)) {\n if (key === 'vector') {\n this.#projection.vector = arg[key] as { name?: string }\n } else if (key === 'document') {\n this.#projection.document = arg[key] as { field?: string }\n } else if (key === 'metadata') {\n this.#projection.metadata = arg[key] as { fields?: string[] }\n } else if (key === 'id') {\n this.#projection.id = true\n }\n }\n }\n }\n return this\n }\n\n limit(n: number): this {\n this.#topK = n\n return this\n }\n\n offset(n: number): this {\n this.#offset = n\n return this\n }\n\n /**\n * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`.\n * Universal across adapters: strongly-consistent backends ignore it (no-op), so a chain\n * written for an eventually-consistent backend keeps working verbatim when the adapter is\n * swapped. Precedence: this > the store's `consistency` option > the adapter's declared\n * `capabilities.consistency.default`. See {@link VectorConsistency}.\n */\n consistency(mode: VectorConsistency): this {\n this.#consistency = mode\n return this\n }\n\n then<TR1 = VectorMatch[], TR2 = never>(\n onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike<TR1>) | null,\n onrejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null\n ): PromiseLike<TR1 | TR2> {\n return this.#run().then(onfulfilled as any, onrejected as any)\n }\n\n async #run(): Promise<VectorMatch[]> {\n if (!this.#selectCalled) {\n throw new E_VECTOR_STORE_PROJECTION_REQUIRED()\n }\n\n const filter = this.buildFilter()\n\n const plan: SearchPlan = {\n collection: this.#collection,\n near: this.#near,\n filter,\n topK: this.#topK,\n offset: this.#offset,\n projection: this.#projection,\n }\n\n this.#validateRawFilters(plan.filter)\n\n return await this.#sink.executeSearch(plan)\n }\n\n async upsert(records: VectorRecord[]): Promise<void> {\n const plan: UpsertPlan = {\n collection: this.#collection,\n records,\n consistency: this.#consistency,\n }\n await this.#sink.executeUpsert(plan)\n }\n\n async delete(): Promise<void> {\n const ids = this.extractIdsFromFilter()\n const filter = this.buildFilter()\n\n const plan: DeletePlan = {\n collection: this.#collection,\n ids: ids.length > 0 ? ids : undefined,\n filter: filter && Object.keys(filter).length > 0 ? filter : undefined,\n consistency: this.#consistency,\n }\n\n await this.#sink.executeDelete(plan)\n }\n\n #validateRawFilters(filter: VectorFilter | undefined): void {\n if (!filter) {\n return\n }\n\n if (isRawFilter(filter)) {\n const raw = filter.$raw as string\n const placeholders = (raw.match(/\\?/g) || []).length\n if (placeholders !== filter.$bindings?.length) {\n throw new E_VECTOR_STORE_RAW_BINDING_MISMATCH([placeholders, filter.$bindings?.length ?? 0])\n }\n return\n }\n\n if ('and' in filter && filter.and) {\n for (const f of filter.and) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('or' in filter && filter.or) {\n for (const f of filter.or) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('not' in filter && filter.not) {\n this.#validateRawFilters(filter.not)\n }\n }\n}\n\nexport { VectorQueryBuilder, FilterBuilder }\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.mjs","names":["#pushOrBranch","#sink","#collection","#topK","#near","#selectCalled","#projection","#offset","#consistency","#run","#validateRawFilters"],"sources":["../../../src/batteries/vector/builder.ts"],"sourcesContent":["/**\n * Knex-style chainable query builder for the vector storage battery.\n *\n * @module @nhtio/adk/batteries/vector/builder\n */\n\nimport { isRawFilter, isFilterCondition } from './filters'\nimport {\n E_VECTOR_STORE_QUERY_CONFLICT,\n E_VECTOR_STORE_PROJECTION_REQUIRED,\n E_VECTOR_STORE_RAW_BINDING_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\n} from './exceptions'\nimport type { VectorRecord, VectorMatch, VectorConsistency } from './types'\nimport type { SearchPlan, UpsertPlan, DeletePlan, Projection } from './plan'\nimport type { VectorFilter, FilterCondition, FilterOperator } from './filters'\n\nconst OP_ALIASES: Record<string, FilterOperator> = {\n '=': 'eq',\n '==': 'eq',\n '===': 'eq',\n '!=': 'ne',\n '<>': 'ne',\n '!==': 'ne',\n '>': 'gt',\n '>=': 'gte',\n '<': 'lt',\n '<=': 'lte',\n 'eq': 'eq',\n 'ne': 'ne',\n 'gt': 'gt',\n 'gte': 'gte',\n 'lt': 'lt',\n 'lte': 'lte',\n 'in': 'in',\n 'nin': 'nin',\n 'exists': 'exists',\n 'contains': 'contains',\n}\nconst normalizeOp = (op: string): FilterOperator => {\n const norm = OP_ALIASES[op]\n if (!norm) throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['builder', op])\n return norm\n}\n\n/**\n * The execution backend a {@link VectorQueryBuilder} drains its assembled plans into. Implemented\n * by the vector store; the builder produces {@link SearchPlan}/{@link UpsertPlan}/{@link DeletePlan}\n * objects and hands them here rather than touching the adapter directly.\n */\nexport interface PlanSink {\n /** Executes an assembled search plan and resolves the matching records. */\n executeSearch(plan: SearchPlan): Promise<VectorMatch[]>\n /** Executes an assembled upsert plan. */\n executeUpsert(plan: UpsertPlan): Promise<void>\n /** Executes an assembled delete plan. */\n executeDelete(plan: DeletePlan): Promise<void>\n}\n\n/**\n * An argument accepted by {@link VectorQueryBuilder.select} — a field name (or `'*'`), a\n * `[field, config]` tuple, or a `{ field: config }` map selecting and configuring projected fields.\n */\nexport type SelectArg =\n | string\n | [string, Record<string, unknown>]\n | Record<string, Record<string, unknown> | true>\n\n/**\n * A callback that receives a fresh filter-only builder, used to express a parenthesized group of\n * conditions — `A AND (B OR C)`, `NOT (…)`, and arbitrary nesting. The callback mutates the builder\n * in place (knex-style); its accumulated conditions become a single nested `VectorFilter`.\n *\n * @see {@link FilterBuilder.where}\n */\nexport type FilterCallback = (qb: FilterBuilder) => void\n\n/**\n * The where-clause surface of the query builder, factored out so a grouping callback can be handed\n * a builder that only exposes filter methods (not `near*`/`select`/`limit` or the terminals).\n *\n * Chained `.where()` ANDs; the first `.orWhere()` snapshots the accumulated AND-list into the first\n * branch of an OR (knex semantics). Any of the where-methods also accepts a {@link FilterCallback}\n * to open a nested group, letting AND and OR mix to any depth.\n */\nclass FilterBuilder {\n protected andConditions: VectorFilter[] = []\n protected orBranches: VectorFilter[][] = []\n\n /** Build a nested group by running `cb` against a fresh {@link FilterBuilder}. */\n protected runGroup(cb: FilterCallback): VectorFilter | undefined {\n const fb = new FilterBuilder()\n cb(fb)\n return fb.buildFilter()\n }\n\n /** Add a parenthesized condition group via a {@link FilterCallback}; ANDed with prior conditions. */\n where(cb: FilterCallback): this\n /** Add a condition `field op value` (or `field = value` when `c` is omitted); ANDed with prior conditions. */\n where(a: string, b?: unknown, c?: unknown): this\n /** Add equality conditions for each key of `obj`; ANDed with prior conditions. */\n where(obj: Record<string, unknown>): this\n where(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof a === 'function') {\n const group = this.runGroup(a)\n if (group !== undefined) {\n this.andConditions.push(group)\n }\n return this\n }\n if (typeof a === 'object' && !Array.isArray(a)) {\n for (const key of Object.keys(a)) {\n this.andConditions.push({\n field: key,\n op: 'eq',\n value: a[key] as FilterCondition['value'],\n })\n }\n return this\n }\n const field = a as string\n const value = b !== undefined ? (c !== undefined ? c : b) : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.andConditions.push({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n /** Alias of {@link FilterBuilder.where} (callback group form) for readability in a chain. */\n andWhere(cb: FilterCallback): this\n /** Alias of {@link FilterBuilder.where} (`field op value` form) for readability in a chain. */\n andWhere(a: string, b?: unknown, c?: unknown): this\n /** Alias of {@link FilterBuilder.where} (object form) for readability in a chain. */\n andWhere(obj: Record<string, unknown>): this\n andWhere(a: string | Record<string, unknown> | FilterCallback, b?: unknown, c?: unknown): this {\n return this.where(a as any, b, c)\n }\n\n /**\n * Open a new OR branch holding a single filter. The accumulated AND-list is contributed as the\n * first OR-group by {@link buildFilter}, so each branch carries only its own condition(s) — that\n * is what makes `where(A).where(B).orWhere(C)` resolve to `(A AND B) OR C`.\n */\n #pushOrBranch(filter: VectorFilter): void {\n this.orBranches.push([filter])\n }\n\n /** Open a new OR branch holding a parenthesized condition group via a {@link FilterCallback}. */\n orWhere(cb: FilterCallback): this\n /** Open a new OR branch holding the equality condition `field = value`. */\n orWhere(field: string, value: unknown): this\n /** Open a new OR branch holding the condition `field op value`. */\n orWhere(field: string, op: FilterOperator, value: unknown): this\n orWhere(field: string | FilterCallback, b?: unknown, c?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch(group)\n }\n return this\n }\n const value = c !== undefined ? c : b\n const op = c !== undefined ? normalizeOp(b as string) : 'eq'\n this.#pushOrBranch({ field, op, value: value as FilterCondition['value'] })\n return this\n }\n\n /** AND a negated parenthesized condition group via a {@link FilterCallback}. */\n whereNot(cb: FilterCallback): this\n /** AND the negated equality condition `field != value`. */\n whereNot(field: string, value: unknown): this\n whereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.andConditions.push({ not: group })\n }\n return this\n }\n return this.where(field, 'ne', value as FilterCondition['value'])\n }\n\n /** Open a new OR branch holding a negated parenthesized condition group via a {@link FilterCallback}. */\n orWhereNot(cb: FilterCallback): this\n /** Open a new OR branch holding the negated equality condition `field != value`. */\n orWhereNot(field: string, value: unknown): this\n orWhereNot(field: string | FilterCallback, value?: unknown): this {\n if (typeof field === 'function') {\n const group = this.runGroup(field)\n if (group !== undefined) {\n this.#pushOrBranch({ not: group })\n }\n return this\n }\n return this.orWhere(field, 'ne', value)\n }\n\n /** AND the condition that `field`'s value is one of `values`. */\n whereIn(field: string, values: unknown[]): this {\n return this.where(field, 'in', values as FilterCondition['value'])\n }\n\n /** AND the condition that `field`'s value is none of `values`. */\n whereNotIn(field: string, values: unknown[]): this {\n return this.where(field, 'nin', values as FilterCondition['value'])\n }\n\n /** AND the condition that `field` is absent (does not exist). */\n whereNull(field: string): this {\n return this.where(field, 'exists', false as FilterCondition['value'])\n }\n\n /** AND the condition that `field` is present (exists). */\n whereExists(field: string): this {\n return this.where(field, 'exists', true as FilterCondition['value'])\n }\n\n /** AND a raw, adapter-dialect filter expressed as SQL text plus positional `bindings`. */\n whereRaw(sql: string, bindings?: unknown[]): this\n /** AND a raw, adapter-dialect filter expressed as a `{ $dialect, $raw, $bindings }` object. */\n whereRaw(rawObj: { $dialect: string; $raw: unknown; $bindings?: unknown[] }): this\n whereRaw(\n sqlOrObj: string | { $dialect: string; $raw: unknown; $bindings?: unknown[] },\n bindings?: unknown[]\n ): this {\n if (typeof sqlOrObj === 'object') {\n this.andConditions.push({\n $dialect: sqlOrObj.$dialect,\n $raw: sqlOrObj.$raw,\n $bindings: sqlOrObj.$bindings ?? [],\n })\n } else {\n this.andConditions.push({ $dialect: 'sql', $raw: sqlOrObj, $bindings: bindings ?? [] })\n }\n return this\n }\n\n protected buildFilter(): VectorFilter | undefined {\n if (this.andConditions.length === 0 && this.orBranches.length === 0) {\n return undefined\n }\n\n if (this.orBranches.length > 0) {\n const orGroups: VectorFilter[][] = []\n if (this.andConditions.length > 0) {\n orGroups.push(this.andConditions)\n }\n for (const branch of this.orBranches) {\n if (branch.length > 0) {\n orGroups.push(branch)\n }\n }\n if (orGroups.length === 1) {\n return { and: orGroups[0] }\n }\n return { or: orGroups.map((conds) => ({ and: conds })) }\n }\n\n return { and: this.andConditions }\n }\n\n protected extractIdsFromFilter(): string[] {\n const ids: string[] = []\n const only = this.andConditions.length === 1 ? this.andConditions[0] : undefined\n if (\n only &&\n isFilterCondition(only) &&\n only.field === 'id' &&\n only.op === 'in' &&\n Array.isArray(only.value)\n ) {\n ids.push(...(only.value as string[]))\n }\n return ids\n }\n}\n\nclass VectorQueryBuilder extends FilterBuilder implements PromiseLike<VectorMatch[]> {\n #sink: PlanSink\n #collection: string\n #near: { vector: number[] } | { serverText: string } | { id: string } | undefined\n #projection: Projection = { id: false, vector: false, document: false, metadata: false }\n #topK: number\n #offset: number = 0\n #selectCalled: boolean = false\n #consistency: VectorConsistency | undefined\n\n constructor(sink: PlanSink, collection: string, defaultTopK: number) {\n super()\n this.#sink = sink\n this.#collection = collection\n this.#topK = defaultTopK\n }\n\n /**\n * Search by nearest neighbours to a client-supplied query `vector`. Mutually exclusive with the\n * other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearVector(vector: number[]): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { vector }\n return this\n }\n\n /**\n * Search by nearest neighbours to `text`, embedded server-side by the backend. Mutually exclusive\n * with the other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearText(text: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { serverText: text }\n return this\n }\n\n /**\n * Search by nearest neighbours to the stored vector of the record with the given `id`. Mutually\n * exclusive with the other `near*` clauses.\n *\n * @throws {@link @nhtio/adk/batteries!E_VECTOR_STORE_QUERY_CONFLICT} when a `near*` clause is already set.\n */\n nearId(id: string): this {\n if (this.#near !== undefined) {\n throw new E_VECTOR_STORE_QUERY_CONFLICT(['a near* clause was already set'])\n }\n this.#near = { id }\n return this\n }\n\n /**\n * Declare which fields each match projects (id / vector / document / metadata). Required before a\n * search terminal runs. Accepts {@link SelectArg}s: `'*'`, field names, `[field, config]` tuples,\n * or `{ field: config }` maps.\n */\n select(...args: SelectArg[]): this {\n this.#selectCalled = true\n for (const arg of args) {\n if (typeof arg === 'string') {\n if (arg === '*') {\n this.#projection = { id: true, vector: {}, document: {}, metadata: {} }\n } else {\n if (arg === 'id') {\n this.#projection.id = true\n } else if (arg === 'vector') {\n this.#projection.vector = {}\n } else if (arg === 'document') {\n this.#projection.document = {}\n } else if (arg === 'metadata') {\n this.#projection.metadata = {}\n }\n }\n } else if (Array.isArray(arg)) {\n const [field, config] = arg\n if (field === 'vector') {\n this.#projection.vector = config as { name?: string }\n } else if (field === 'document') {\n this.#projection.document = config as { field?: string }\n } else if (field === 'metadata') {\n this.#projection.metadata = config as { fields?: string[] }\n } else if (field === 'id') {\n this.#projection.id = true\n }\n } else if (typeof arg === 'object') {\n for (const key of Object.keys(arg)) {\n if (key === 'vector') {\n this.#projection.vector = arg[key] as { name?: string }\n } else if (key === 'document') {\n this.#projection.document = arg[key] as { field?: string }\n } else if (key === 'metadata') {\n this.#projection.metadata = arg[key] as { fields?: string[] }\n } else if (key === 'id') {\n this.#projection.id = true\n }\n }\n }\n }\n return this\n }\n\n /** Cap the number of matches returned (the search `topK`). */\n limit(n: number): this {\n this.#topK = n\n return this\n }\n\n /** Skip the first `n` matches before returning results. */\n offset(n: number): this {\n this.#offset = n\n return this\n }\n\n /**\n * Per-operation read-after-write override for the terminal `.upsert()` / `.delete()`.\n * Universal across adapters: strongly-consistent backends ignore it (no-op), so a chain\n * written for an eventually-consistent backend keeps working verbatim when the adapter is\n * swapped. Precedence: this > the store's `consistency` option > the adapter's declared\n * `capabilities.consistency.default`. See {@link VectorConsistency}.\n */\n consistency(mode: VectorConsistency): this {\n this.#consistency = mode\n return this\n }\n\n then<TR1 = VectorMatch[], TR2 = never>(\n onfulfilled?: ((value: VectorMatch[]) => TR1 | PromiseLike<TR1>) | null,\n onrejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null\n ): PromiseLike<TR1 | TR2> {\n return this.#run().then(onfulfilled as any, onrejected as any)\n }\n\n async #run(): Promise<VectorMatch[]> {\n if (!this.#selectCalled) {\n throw new E_VECTOR_STORE_PROJECTION_REQUIRED()\n }\n\n const filter = this.buildFilter()\n\n const plan: SearchPlan = {\n collection: this.#collection,\n near: this.#near,\n filter,\n topK: this.#topK,\n offset: this.#offset,\n projection: this.#projection,\n }\n\n this.#validateRawFilters(plan.filter)\n\n return await this.#sink.executeSearch(plan)\n }\n\n /** Terminal: insert or replace `records` in the collection. */\n async upsert(records: VectorRecord[]): Promise<void> {\n const plan: UpsertPlan = {\n collection: this.#collection,\n records,\n consistency: this.#consistency,\n }\n await this.#sink.executeUpsert(plan)\n }\n\n /** Terminal: delete records matching the accumulated filter (or the `id IN [...]` fast path). */\n async delete(): Promise<void> {\n const ids = this.extractIdsFromFilter()\n const filter = this.buildFilter()\n\n const plan: DeletePlan = {\n collection: this.#collection,\n ids: ids.length > 0 ? ids : undefined,\n filter: filter && Object.keys(filter).length > 0 ? filter : undefined,\n consistency: this.#consistency,\n }\n\n await this.#sink.executeDelete(plan)\n }\n\n #validateRawFilters(filter: VectorFilter | undefined): void {\n if (!filter) {\n return\n }\n\n if (isRawFilter(filter)) {\n const raw = filter.$raw as string\n const placeholders = (raw.match(/\\?/g) || []).length\n if (placeholders !== filter.$bindings?.length) {\n throw new E_VECTOR_STORE_RAW_BINDING_MISMATCH([placeholders, filter.$bindings?.length ?? 0])\n }\n return\n }\n\n if ('and' in filter && filter.and) {\n for (const f of filter.and) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('or' in filter && filter.or) {\n for (const f of filter.or) {\n this.#validateRawFilters(f)\n }\n }\n\n if ('not' in filter && filter.not) {\n this.#validateRawFilters(filter.not)\n }\n }\n}\n\nexport { VectorQueryBuilder, FilterBuilder }\n"],"mappings":"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"}