andnp-searchkernel 0.1.0__tar.gz

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 (260) hide show
  1. andnp_searchkernel-0.1.0/.github/workflows/ci.yml +40 -0
  2. andnp_searchkernel-0.1.0/.github/workflows/publish.yml +32 -0
  3. andnp_searchkernel-0.1.0/.gitignore +54 -0
  4. andnp_searchkernel-0.1.0/LICENSE +21 -0
  5. andnp_searchkernel-0.1.0/PKG-INFO +34 -0
  6. andnp_searchkernel-0.1.0/README.md +11 -0
  7. andnp_searchkernel-0.1.0/pyproject.toml +79 -0
  8. andnp_searchkernel-0.1.0/searchkernel/__init__.py +19 -0
  9. andnp_searchkernel-0.1.0/searchkernel/adapters/cache/__init__.py +6 -0
  10. andnp_searchkernel-0.1.0/searchkernel/adapters/cache/memory_lru.py +71 -0
  11. andnp_searchkernel-0.1.0/searchkernel/adapters/cache/sqlite.py +113 -0
  12. andnp_searchkernel-0.1.0/searchkernel/adapters/embedding/__init__.py +5 -0
  13. andnp_searchkernel-0.1.0/searchkernel/adapters/embedding/huggingface.py +89 -0
  14. andnp_searchkernel-0.1.0/searchkernel/adapters/llm/__init__.py +5 -0
  15. andnp_searchkernel-0.1.0/searchkernel/adapters/llm/copilot.py +120 -0
  16. andnp_searchkernel-0.1.0/searchkernel/adapters/rerank/__init__.py +5 -0
  17. andnp_searchkernel-0.1.0/searchkernel/adapters/rerank/huggingface.py +158 -0
  18. andnp_searchkernel-0.1.0/searchkernel/adapters/stores/__init__.py +19 -0
  19. andnp_searchkernel-0.1.0/searchkernel/adapters/stores/pgvector.py +747 -0
  20. andnp_searchkernel-0.1.0/searchkernel/adapters/stores/pgvector_index.py +375 -0
  21. andnp_searchkernel-0.1.0/searchkernel/chunking/__init__.py +6 -0
  22. andnp_searchkernel-0.1.0/searchkernel/chunking/base.py +9 -0
  23. andnp_searchkernel-0.1.0/searchkernel/chunking/factory.py +7 -0
  24. andnp_searchkernel-0.1.0/searchkernel/chunking/header_chunker.py +668 -0
  25. andnp_searchkernel-0.1.0/searchkernel/compression/__init__.py +5 -0
  26. andnp_searchkernel-0.1.0/searchkernel/compression/thresholding.py +5 -0
  27. andnp_searchkernel-0.1.0/searchkernel/domain/__init__.py +41 -0
  28. andnp_searchkernel-0.1.0/searchkernel/domain/graph_policy.py +40 -0
  29. andnp_searchkernel-0.1.0/searchkernel/domain/models.py +374 -0
  30. andnp_searchkernel-0.1.0/searchkernel/domain/status_policy.py +34 -0
  31. andnp_searchkernel-0.1.0/searchkernel/domain/timestamp_policy.py +36 -0
  32. andnp_searchkernel-0.1.0/searchkernel/embeddings.py +53 -0
  33. andnp_searchkernel-0.1.0/searchkernel/eval/__init__.py +1 -0
  34. andnp_searchkernel-0.1.0/searchkernel/eval/golden.py +118 -0
  35. andnp_searchkernel-0.1.0/searchkernel/eval/metrics.py +131 -0
  36. andnp_searchkernel-0.1.0/searchkernel/eval/runner.py +259 -0
  37. andnp_searchkernel-0.1.0/searchkernel/indexing/bootstrap_checkpoint.py +409 -0
  38. andnp_searchkernel-0.1.0/searchkernel/indexing/bootstrap_snapshot.py +115 -0
  39. andnp_searchkernel-0.1.0/searchkernel/indexing/core.py +181 -0
  40. andnp_searchkernel-0.1.0/searchkernel/indexing/discovery.py +169 -0
  41. andnp_searchkernel-0.1.0/searchkernel/indexing/embedding_cache.py +206 -0
  42. andnp_searchkernel-0.1.0/searchkernel/indexing/git_ingestion.py +56 -0
  43. andnp_searchkernel-0.1.0/searchkernel/indexing/implicit_graph.py +156 -0
  44. andnp_searchkernel-0.1.0/searchkernel/indexing/manifest.py +65 -0
  45. andnp_searchkernel-0.1.0/searchkernel/indexing/migration.py +116 -0
  46. andnp_searchkernel-0.1.0/searchkernel/indexing/reconciler.py +179 -0
  47. andnp_searchkernel-0.1.0/searchkernel/indexing/runtime_readiness.py +134 -0
  48. andnp_searchkernel-0.1.0/searchkernel/indexing/semantic.py +288 -0
  49. andnp_searchkernel-0.1.0/searchkernel/indexing/stages.py +204 -0
  50. andnp_searchkernel-0.1.0/searchkernel/indexing/submission.py +60 -0
  51. andnp_searchkernel-0.1.0/searchkernel/indices/__init__.py +1 -0
  52. andnp_searchkernel-0.1.0/searchkernel/indices/_corruption.py +26 -0
  53. andnp_searchkernel-0.1.0/searchkernel/indices/_writer_utils.py +22 -0
  54. andnp_searchkernel-0.1.0/searchkernel/indices/graph.py +850 -0
  55. andnp_searchkernel-0.1.0/searchkernel/indices/hash_store.py +151 -0
  56. andnp_searchkernel-0.1.0/searchkernel/indices/keyword.py +874 -0
  57. andnp_searchkernel-0.1.0/searchkernel/indices/protocol.py +29 -0
  58. andnp_searchkernel-0.1.0/searchkernel/indices/vector.py +1942 -0
  59. andnp_searchkernel-0.1.0/searchkernel/indices/vocabulary_state.py +147 -0
  60. andnp_searchkernel-0.1.0/searchkernel/pipeline/__init__.py +11 -0
  61. andnp_searchkernel-0.1.0/searchkernel/pipeline/default_query_spec.py +54 -0
  62. andnp_searchkernel-0.1.0/searchkernel/pipeline/executor.py +63 -0
  63. andnp_searchkernel-0.1.0/searchkernel/pipeline/registry.py +165 -0
  64. andnp_searchkernel-0.1.0/searchkernel/pipeline/spec.py +32 -0
  65. andnp_searchkernel-0.1.0/searchkernel/pipeline/stage.py +57 -0
  66. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/__init__.py +12 -0
  67. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/apply_move.py +138 -0
  68. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/calibrate.py +34 -0
  69. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/chunk.py +41 -0
  70. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/community_boost.py +74 -0
  71. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/dedup_content_hash.py +30 -0
  72. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/dedup_ngram.py +38 -0
  73. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/dedup_rerank.py +129 -0
  74. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/dedup_similarity.py +40 -0
  75. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/detect_moves.py +80 -0
  76. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/discover.py +67 -0
  77. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/doc_limit.py +31 -0
  78. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/effective_top_k.py +75 -0
  79. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/fusion.py +40 -0
  80. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/graph_expand.py +62 -0
  81. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/hydrate.py +86 -0
  82. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/index.py +68 -0
  83. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/parent_expansion.py +89 -0
  84. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/project_filter.py +54 -0
  85. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/project_uplift.py +68 -0
  86. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/provenance.py +59 -0
  87. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/rag_fusion.py +100 -0
  88. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/recency_boost.py +42 -0
  89. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/repair.py +52 -0
  90. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/rerank.py +52 -0
  91. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/retrieve.py +66 -0
  92. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/routing.py +52 -0
  93. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/rrf_fuse.py +27 -0
  94. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/seed_bookkeeping.py +127 -0
  95. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/source_filter.py +48 -0
  96. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/strategy_results.py +78 -0
  97. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/tag_expansion.py +95 -0
  98. andnp_searchkernel-0.1.0/searchkernel/pipeline/stages/threshold.py +27 -0
  99. andnp_searchkernel-0.1.0/searchkernel/ports/__init__.py +39 -0
  100. andnp_searchkernel-0.1.0/searchkernel/ports/chunking_config.py +20 -0
  101. andnp_searchkernel-0.1.0/searchkernel/ports/content_source.py +85 -0
  102. andnp_searchkernel-0.1.0/searchkernel/ports/embedding.py +43 -0
  103. andnp_searchkernel-0.1.0/searchkernel/ports/index_manager.py +27 -0
  104. andnp_searchkernel-0.1.0/searchkernel/ports/llm.py +40 -0
  105. andnp_searchkernel-0.1.0/searchkernel/ports/orchestrator_config.py +40 -0
  106. andnp_searchkernel-0.1.0/searchkernel/ports/rerank.py +34 -0
  107. andnp_searchkernel-0.1.0/searchkernel/ports/search.py +46 -0
  108. andnp_searchkernel-0.1.0/searchkernel/ports/stores.py +177 -0
  109. andnp_searchkernel-0.1.0/searchkernel/runtime/__init__.py +13 -0
  110. andnp_searchkernel-0.1.0/searchkernel/runtime/cache.py +133 -0
  111. andnp_searchkernel-0.1.0/searchkernel/runtime/fanout.py +75 -0
  112. andnp_searchkernel-0.1.0/searchkernel/runtime/federation.py +84 -0
  113. andnp_searchkernel-0.1.0/searchkernel/runtime/query_embedding_cache.py +148 -0
  114. andnp_searchkernel-0.1.0/searchkernel/runtime/registry.py +39 -0
  115. andnp_searchkernel-0.1.0/searchkernel/runtime/reindex.py +238 -0
  116. andnp_searchkernel-0.1.0/searchkernel/runtime/trace.py +119 -0
  117. andnp_searchkernel-0.1.0/searchkernel/search/__init__.py +24 -0
  118. andnp_searchkernel-0.1.0/searchkernel/search/base_orchestrator.py +140 -0
  119. andnp_searchkernel-0.1.0/searchkernel/search/calibration.py +26 -0
  120. andnp_searchkernel-0.1.0/searchkernel/search/chunk_hydrator.py +317 -0
  121. andnp_searchkernel-0.1.0/searchkernel/search/classifier.py +104 -0
  122. andnp_searchkernel-0.1.0/searchkernel/search/community.py +29 -0
  123. andnp_searchkernel-0.1.0/searchkernel/search/dedup.py +134 -0
  124. andnp_searchkernel-0.1.0/searchkernel/search/edge_types.py +57 -0
  125. andnp_searchkernel-0.1.0/searchkernel/search/filters.py +48 -0
  126. andnp_searchkernel-0.1.0/searchkernel/search/fusion.py +34 -0
  127. andnp_searchkernel-0.1.0/searchkernel/search/graph_expansion.py +80 -0
  128. andnp_searchkernel-0.1.0/searchkernel/search/hyde.py +32 -0
  129. andnp_searchkernel-0.1.0/searchkernel/search/normalization.py +29 -0
  130. andnp_searchkernel-0.1.0/searchkernel/search/orchestrator.py +756 -0
  131. andnp_searchkernel-0.1.0/searchkernel/search/path_utils.py +186 -0
  132. andnp_searchkernel-0.1.0/searchkernel/search/pipeline.py +129 -0
  133. andnp_searchkernel-0.1.0/searchkernel/search/query_execution.py +119 -0
  134. andnp_searchkernel-0.1.0/searchkernel/search/reranker.py +126 -0
  135. andnp_searchkernel-0.1.0/searchkernel/search/result_cache.py +47 -0
  136. andnp_searchkernel-0.1.0/searchkernel/search/score_pipeline.py +142 -0
  137. andnp_searchkernel-0.1.0/searchkernel/search/tag_expansion.py +173 -0
  138. andnp_searchkernel-0.1.0/searchkernel/search/time_scoring.py +100 -0
  139. andnp_searchkernel-0.1.0/searchkernel/search/types.py +12 -0
  140. andnp_searchkernel-0.1.0/searchkernel/search/utils.py +55 -0
  141. andnp_searchkernel-0.1.0/searchkernel/search/variance.py +42 -0
  142. andnp_searchkernel-0.1.0/searchkernel/storage/__init__.py +0 -0
  143. andnp_searchkernel-0.1.0/searchkernel/storage/db.py +100 -0
  144. andnp_searchkernel-0.1.0/searchkernel/utils/__init__.py +58 -0
  145. andnp_searchkernel-0.1.0/searchkernel/utils/atomic_io.py +73 -0
  146. andnp_searchkernel-0.1.0/searchkernel/utils/circuit_breaker.py +207 -0
  147. andnp_searchkernel-0.1.0/searchkernel/utils/similarity.py +24 -0
  148. andnp_searchkernel-0.1.0/tests/__init__.py +1 -0
  149. andnp_searchkernel-0.1.0/tests/conftest.py +343 -0
  150. andnp_searchkernel-0.1.0/tests/integration/__init__.py +0 -0
  151. andnp_searchkernel-0.1.0/tests/integration/conftest.py +35 -0
  152. andnp_searchkernel-0.1.0/tests/integration/test_hf_embedding_pgvector.py +107 -0
  153. andnp_searchkernel-0.1.0/tests/integration/test_pgvector_index.py +237 -0
  154. andnp_searchkernel-0.1.0/tests/integration/test_pgvector_store.py +486 -0
  155. andnp_searchkernel-0.1.0/tests/regression/__init__.py +0 -0
  156. andnp_searchkernel-0.1.0/tests/unit/__init__.py +0 -0
  157. andnp_searchkernel-0.1.0/tests/unit/pipeline/__init__.py +0 -0
  158. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/__init__.py +0 -0
  159. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_apply_move.py +146 -0
  160. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_calibrate.py +31 -0
  161. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_community_boost.py +73 -0
  162. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_dedup_content_hash.py +41 -0
  163. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_dedup_ngram.py +52 -0
  164. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_dedup_rerank.py +64 -0
  165. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_dedup_similarity.py +54 -0
  166. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_detect_moves.py +89 -0
  167. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_discover.py +65 -0
  168. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_doc_limit.py +36 -0
  169. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_effective_top_k.py +89 -0
  170. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_fusion.py +42 -0
  171. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_graph_expand.py +80 -0
  172. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_hydrate.py +84 -0
  173. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_index.py +72 -0
  174. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_project_filter.py +44 -0
  175. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_project_uplift.py +60 -0
  176. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_provenance.py +73 -0
  177. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_rag_fusion.py +96 -0
  178. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_recency_boost.py +66 -0
  179. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_repair.py +66 -0
  180. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_rerank.py +81 -0
  181. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_retrieve.py +86 -0
  182. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_routing.py +47 -0
  183. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_rrf_fuse.py +39 -0
  184. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_seed_bookkeeping.py +75 -0
  185. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_source_filter.py +36 -0
  186. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_strategy_results.py +61 -0
  187. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_tag_expansion.py +108 -0
  188. andnp_searchkernel-0.1.0/tests/unit/pipeline/stages/test_threshold.py +31 -0
  189. andnp_searchkernel-0.1.0/tests/unit/pipeline/test_default_query_spec.py +27 -0
  190. andnp_searchkernel-0.1.0/tests/unit/pipeline/test_executor.py +94 -0
  191. andnp_searchkernel-0.1.0/tests/unit/pipeline/test_registry.py +228 -0
  192. andnp_searchkernel-0.1.0/tests/unit/pipeline/test_spec.py +27 -0
  193. andnp_searchkernel-0.1.0/tests/unit/pipeline/test_stage.py +60 -0
  194. andnp_searchkernel-0.1.0/tests/unit/search/__init__.py +0 -0
  195. andnp_searchkernel-0.1.0/tests/unit/search/test_graph_expansion.py +62 -0
  196. andnp_searchkernel-0.1.0/tests/unit/test_atomic_io.py +190 -0
  197. andnp_searchkernel-0.1.0/tests/unit/test_bootstrap_checkpoint.py +91 -0
  198. andnp_searchkernel-0.1.0/tests/unit/test_bootstrap_checkpoint_semantic.py +269 -0
  199. andnp_searchkernel-0.1.0/tests/unit/test_bootstrap_snapshot.py +171 -0
  200. andnp_searchkernel-0.1.0/tests/unit/test_cache_store_adapters.py +232 -0
  201. andnp_searchkernel-0.1.0/tests/unit/test_cached_decorator.py +262 -0
  202. andnp_searchkernel-0.1.0/tests/unit/test_calibration.py +258 -0
  203. andnp_searchkernel-0.1.0/tests/unit/test_chunk_hashing.py +115 -0
  204. andnp_searchkernel-0.1.0/tests/unit/test_classifier.py +93 -0
  205. andnp_searchkernel-0.1.0/tests/unit/test_community.py +177 -0
  206. andnp_searchkernel-0.1.0/tests/unit/test_copilot_llm_provider.py +178 -0
  207. andnp_searchkernel-0.1.0/tests/unit/test_corruption_detection.py +17 -0
  208. andnp_searchkernel-0.1.0/tests/unit/test_cross_process.py +108 -0
  209. andnp_searchkernel-0.1.0/tests/unit/test_db_schema.py +280 -0
  210. andnp_searchkernel-0.1.0/tests/unit/test_dedup.py +605 -0
  211. andnp_searchkernel-0.1.0/tests/unit/test_edge_types.py +274 -0
  212. andnp_searchkernel-0.1.0/tests/unit/test_eval_golden.py +242 -0
  213. andnp_searchkernel-0.1.0/tests/unit/test_eval_metrics.py +242 -0
  214. andnp_searchkernel-0.1.0/tests/unit/test_eval_runner.py +182 -0
  215. andnp_searchkernel-0.1.0/tests/unit/test_fanout.py +248 -0
  216. andnp_searchkernel-0.1.0/tests/unit/test_federation.py +212 -0
  217. andnp_searchkernel-0.1.0/tests/unit/test_file_discovery.py +134 -0
  218. andnp_searchkernel-0.1.0/tests/unit/test_filters.py +205 -0
  219. andnp_searchkernel-0.1.0/tests/unit/test_fusion.py +112 -0
  220. andnp_searchkernel-0.1.0/tests/unit/test_fusion_scoring.py +234 -0
  221. andnp_searchkernel-0.1.0/tests/unit/test_graph_corruption.py +201 -0
  222. andnp_searchkernel-0.1.0/tests/unit/test_graph_policy.py +21 -0
  223. andnp_searchkernel-0.1.0/tests/unit/test_graph_store.py +398 -0
  224. andnp_searchkernel-0.1.0/tests/unit/test_hash_store.py +290 -0
  225. andnp_searchkernel-0.1.0/tests/unit/test_hf_embedding_provider.py +66 -0
  226. andnp_searchkernel-0.1.0/tests/unit/test_hf_reranker.py +94 -0
  227. andnp_searchkernel-0.1.0/tests/unit/test_hyde.py +253 -0
  228. andnp_searchkernel-0.1.0/tests/unit/test_indexing_stages.py +329 -0
  229. andnp_searchkernel-0.1.0/tests/unit/test_keyword_exclusion.py +128 -0
  230. andnp_searchkernel-0.1.0/tests/unit/test_keyword_index.py +1185 -0
  231. andnp_searchkernel-0.1.0/tests/unit/test_lazy_loading.py +93 -0
  232. andnp_searchkernel-0.1.0/tests/unit/test_legacy_migration.py +165 -0
  233. andnp_searchkernel-0.1.0/tests/unit/test_manifest.py +170 -0
  234. andnp_searchkernel-0.1.0/tests/unit/test_manifest_corruption.py +242 -0
  235. andnp_searchkernel-0.1.0/tests/unit/test_manifest_migration.py +282 -0
  236. andnp_searchkernel-0.1.0/tests/unit/test_path_utils.py +340 -0
  237. andnp_searchkernel-0.1.0/tests/unit/test_query_embedding_cache.py +123 -0
  238. andnp_searchkernel-0.1.0/tests/unit/test_query_expansion.py +467 -0
  239. andnp_searchkernel-0.1.0/tests/unit/test_reconciler.py +466 -0
  240. andnp_searchkernel-0.1.0/tests/unit/test_reranker.py +311 -0
  241. andnp_searchkernel-0.1.0/tests/unit/test_reranker_circuit_breaker.py +228 -0
  242. andnp_searchkernel-0.1.0/tests/unit/test_runtime_readiness.py +83 -0
  243. andnp_searchkernel-0.1.0/tests/unit/test_runtime_trace.py +185 -0
  244. andnp_searchkernel-0.1.0/tests/unit/test_score_pipeline.py +526 -0
  245. andnp_searchkernel-0.1.0/tests/unit/test_search_utils.py +92 -0
  246. andnp_searchkernel-0.1.0/tests/unit/test_semantic_indexing.py +419 -0
  247. andnp_searchkernel-0.1.0/tests/unit/test_semantic_tier_from_progress.py +59 -0
  248. andnp_searchkernel-0.1.0/tests/unit/test_similarity.py +20 -0
  249. andnp_searchkernel-0.1.0/tests/unit/test_source_registry.py +89 -0
  250. andnp_searchkernel-0.1.0/tests/unit/test_status_policy.py +25 -0
  251. andnp_searchkernel-0.1.0/tests/unit/test_time_scoring.py +361 -0
  252. andnp_searchkernel-0.1.0/tests/unit/test_timestamp_policy.py +30 -0
  253. andnp_searchkernel-0.1.0/tests/unit/test_variance.py +329 -0
  254. andnp_searchkernel-0.1.0/tests/unit/test_vector_circuit_breaker.py +531 -0
  255. andnp_searchkernel-0.1.0/tests/unit/test_vector_corruption.py +328 -0
  256. andnp_searchkernel-0.1.0/tests/unit/test_vector_exclusion.py +128 -0
  257. andnp_searchkernel-0.1.0/tests/unit/test_vector_parallel_embeddings.py +343 -0
  258. andnp_searchkernel-0.1.0/tests/unit/test_vector_race_condition.py +218 -0
  259. andnp_searchkernel-0.1.0/tests/unit/test_vector_sqlite.py +160 -0
  260. andnp_searchkernel-0.1.0/tests/unit/test_vector_threading.py +25 -0
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint-and-test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v3
26
+
27
+ - name: Sync dependencies
28
+ run: uv sync
29
+
30
+ - name: Lint with ruff
31
+ run: uv run ruff check .
32
+
33
+ - name: Type check
34
+ run: uv run pyright
35
+
36
+ - name: Check imports with import-linter
37
+ run: uv run lint-imports
38
+
39
+ - name: Run unit tests
40
+ run: uv run pytest -m unit -v
@@ -0,0 +1,32 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ name: Publish to PyPI
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ id-token: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.13"
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v3
25
+
26
+ - name: Build package
27
+ run: uv build
28
+
29
+ - name: Publish to PyPI
30
+ uses: pypa/gh-action-pypi-publish@release/v1
31
+ with:
32
+ packages-dir: dist/
@@ -0,0 +1,54 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ pip-wheel-metadata/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Virtual environments
27
+ .venv/
28
+ venv/
29
+ ENV/
30
+ env/
31
+ .env
32
+
33
+ # IDE
34
+ .vscode/
35
+ .idea/
36
+ *.swp
37
+ *.swo
38
+ *~
39
+ .DS_Store
40
+
41
+ # Testing
42
+ .pytest_cache/
43
+ .coverage
44
+ htmlcov/
45
+ .tox/
46
+ .hypothesis/
47
+
48
+ # Tools
49
+ .ruff_cache/
50
+ .mypy_cache/
51
+ .pytype/
52
+
53
+ # Lock files (generated by uv)
54
+ uv.lock
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 andnp-searchkernel contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: andnp-searchkernel
3
+ Version: 0.1.0
4
+ Summary: Source-agnostic search/indexing kernel: domain-agnostic content ingestion, hybrid vector+keyword+graph search, pluggable embedding/LLM/reranker providers.
5
+ Project-URL: Homepage, https://github.com/andnp/andnp-searchkernel
6
+ Project-URL: Documentation, https://github.com/andnp/andnp-searchkernel/tree/main/docs
7
+ Project-URL: Repository, https://github.com/andnp/andnp-searchkernel.git
8
+ Project-URL: Issues, https://github.com/andnp/andnp-searchkernel/issues
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.13
11
+ Requires-Dist: faiss-cpu>=1.9.0
12
+ Requires-Dist: llama-index-core>=0.12.0
13
+ Requires-Dist: llama-index-embeddings-huggingface>=0.4.0
14
+ Requires-Dist: llama-index-vector-stores-faiss>=0.3.0
15
+ Requires-Dist: psycopg2-binary>=2.9.0
16
+ Requires-Dist: pyyaml>=6.0.2
17
+ Requires-Dist: sentence-transformers>=3.0.0
18
+ Requires-Dist: tenacity>=9.0.0
19
+ Requires-Dist: tomlkit>=0.13.0
20
+ Requires-Dist: tree-sitter-markdown>=0.3.2
21
+ Requires-Dist: tree-sitter>=0.23.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # `andnp-searchkernel`
25
+
26
+ A domain-agnostic search/indexing kernel for building hybrid vector + keyword + graph search systems with pluggable embedding, LLM, and reranker providers.
27
+
28
+ ## Status
29
+
30
+ **Pre-alpha, extraction in progress.** This library is being extracted from [`mcp-markdown-ragdocs`](https://github.com/andnp/mcp-markdown-ragdocs) to enable reuse across arbitrary content sources and search backends.
31
+
32
+ ## License
33
+
34
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,11 @@
1
+ # `andnp-searchkernel`
2
+
3
+ A domain-agnostic search/indexing kernel for building hybrid vector + keyword + graph search systems with pluggable embedding, LLM, and reranker providers.
4
+
5
+ ## Status
6
+
7
+ **Pre-alpha, extraction in progress.** This library is being extracted from [`mcp-markdown-ragdocs`](https://github.com/andnp/mcp-markdown-ragdocs) to enable reuse across arbitrary content sources and search backends.
8
+
9
+ ## License
10
+
11
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "andnp-searchkernel"
7
+ version = "0.1.0"
8
+ description = "Source-agnostic search/indexing kernel: domain-agnostic content ingestion, hybrid vector+keyword+graph search, pluggable embedding/LLM/reranker providers."
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "llama-index-core>=0.12.0",
13
+ "llama-index-embeddings-huggingface>=0.4.0",
14
+ "llama-index-vector-stores-faiss>=0.3.0",
15
+ "faiss-cpu>=1.9.0",
16
+ "sentence-transformers>=3.0.0",
17
+ "tenacity>=9.0.0",
18
+ "psycopg2-binary>=2.9.0",
19
+ "pyyaml>=6.0.2",
20
+ "tomlkit>=0.13.0",
21
+ "tree-sitter>=0.23.0",
22
+ "tree-sitter-markdown>=0.3.2",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/andnp/andnp-searchkernel"
27
+ Documentation = "https://github.com/andnp/andnp-searchkernel/tree/main/docs"
28
+ Repository = "https://github.com/andnp/andnp-searchkernel.git"
29
+ Issues = "https://github.com/andnp/andnp-searchkernel/issues"
30
+
31
+ [dependency-groups]
32
+ dev = [
33
+ "pyright>=1.1.407",
34
+ "pytest>=9.0.2",
35
+ "pytest-asyncio>=0.24.0",
36
+ "pytest-cov>=6.0.0",
37
+ "pytest-xdist>=3.5.0",
38
+ "ruff>=0.14.10",
39
+ "ty>=0.0.12",
40
+ "import-linter>=2.0",
41
+ ]
42
+
43
+ [tool.uv]
44
+ package = true
45
+
46
+ [tool.hatch.build.targets.wheel]
47
+ packages = ["searchkernel"]
48
+
49
+ [tool.pytest.ini_options]
50
+ pythonpath = "."
51
+ addopts = "-n 4 --dist worksteal"
52
+ markers = [
53
+ "serial: marks tests that must run serially (not in parallel)",
54
+ "unit: marks unit tests (fast, isolated)",
55
+ "integration: marks integration tests (involve multiple components)",
56
+ "e2e: marks end-to-end tests (full system tests)",
57
+ "slow: marks slow tests (>5s, load models or process large datasets)",
58
+ "real_embeddings: marks tests that require real embedding models (not fake deterministic embeddings)",
59
+ ]
60
+
61
+ [tool.importlinter]
62
+ root_packages = ["searchkernel"]
63
+ default_mapping = "searchkernel"
64
+
65
+ [[tool.importlinter.contracts]]
66
+ name = "domain and ports are inward-only"
67
+ type = "forbidden"
68
+ source_modules = ["searchkernel.domain", "searchkernel.ports"]
69
+ forbidden_modules = [
70
+ "searchkernel.adapters",
71
+ "searchkernel.pipeline",
72
+ "searchkernel.search",
73
+ "searchkernel.indices",
74
+ "searchkernel.storage",
75
+ "searchkernel.runtime",
76
+ "searchkernel.eval",
77
+ "searchkernel.compression",
78
+ ]
79
+ ignore_imports = []
@@ -0,0 +1,19 @@
1
+ """
2
+ Source-agnostic search/indexing kernel.
3
+
4
+ A domain-agnostic library for building hybrid vector+keyword+graph search systems
5
+ with pluggable embedding/LLM/reranker providers.
6
+ """
7
+
8
+ from searchkernel.search.orchestrator import SearchOrchestrator
9
+ from searchkernel.search.pipeline import SearchPipelineConfig
10
+ from searchkernel.search.utils import classify_query_type, truncate_content
11
+
12
+ __version__ = "0.1.0"
13
+
14
+ __all__ = [
15
+ "SearchOrchestrator",
16
+ "SearchPipelineConfig",
17
+ "classify_query_type",
18
+ "truncate_content",
19
+ ]
@@ -0,0 +1,6 @@
1
+ """Cache store adapters implementing the CacheStore port."""
2
+
3
+ from searchkernel.adapters.cache.memory_lru import MemoryLRUCacheStore
4
+ from searchkernel.adapters.cache.sqlite import SQLiteCacheStore
5
+
6
+ __all__ = ["MemoryLRUCacheStore", "SQLiteCacheStore"]
@@ -0,0 +1,71 @@
1
+ """In-memory LRU cache store with epoch-based invalidation."""
2
+
3
+ from collections import OrderedDict
4
+ from typing import Any
5
+
6
+
7
+ class MemoryLRUCacheStore:
8
+ """LRU in-memory cache store implementing the CacheStore port.
9
+
10
+ Stores key-value pairs in memory with a bounded size. When capacity is
11
+ exceeded, the least recently used entry is evicted. Entries are tagged
12
+ with an epoch for invalidation support.
13
+ """
14
+
15
+ def __init__(self, max_entries: int = 128):
16
+ """Initialize memory LRU cache store.
17
+
18
+ Args:
19
+ max_entries: Maximum number of entries to store (default 128).
20
+ Must be at least 1.
21
+ """
22
+ self._max_entries = max(1, max_entries)
23
+ self._entries: OrderedDict[str, tuple[Any, int]] = OrderedDict()
24
+
25
+ def get(self, key: str) -> Any | None:
26
+ """Retrieve a cached value.
27
+
28
+ Args:
29
+ key: Cache key.
30
+
31
+ Returns:
32
+ Cached value, or None if not found.
33
+ """
34
+ if key not in self._entries:
35
+ return None
36
+
37
+ value, _epoch = self._entries[key]
38
+ # Move to end to mark as recently used (LRU)
39
+ self._entries.move_to_end(key)
40
+ return value
41
+
42
+ def set(self, key: str, value: Any, epoch: int) -> None:
43
+ """Store a value with an associated epoch.
44
+
45
+ Args:
46
+ key: Cache key.
47
+ value: Value to cache.
48
+ epoch: Index epoch at cache time. Used for invalidation.
49
+ """
50
+ if key in self._entries:
51
+ self._entries.pop(key)
52
+
53
+ self._entries[key] = (value, epoch)
54
+ self._entries.move_to_end(key)
55
+
56
+ # Evict LRU entry if over capacity
57
+ while len(self._entries) > self._max_entries:
58
+ self._entries.popitem(last=False)
59
+
60
+ def invalidate_epoch(self, epoch: int) -> None:
61
+ """Invalidate all entries from an epoch or earlier.
62
+
63
+ Args:
64
+ epoch: Entries with epoch <= this are discarded.
65
+ """
66
+ keys_to_delete = [
67
+ key for key, (_, entry_epoch) in self._entries.items()
68
+ if entry_epoch <= epoch
69
+ ]
70
+ for key in keys_to_delete:
71
+ del self._entries[key]
@@ -0,0 +1,113 @@
1
+ """SQLite-backed cache store with epoch-based invalidation."""
2
+
3
+ import json
4
+ import logging
5
+ import sqlite3
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class SQLiteCacheStore:
13
+ """SQLite-backed cache store implementing the CacheStore port.
14
+
15
+ Persists key-value pairs to a SQLite database. Entries are tagged with
16
+ an epoch for invalidation support. Designed for durability across restarts.
17
+ """
18
+
19
+ def __init__(self, db_path: Path | str):
20
+ """Initialize SQLite cache store.
21
+
22
+ Args:
23
+ db_path: Path to SQLite database file.
24
+ """
25
+ self.db_path = Path(db_path)
26
+ self.db_path.parent.mkdir(parents=True, exist_ok=True)
27
+ self._init_schema()
28
+
29
+ def _init_schema(self) -> None:
30
+ """Create the cache table if it doesn't exist."""
31
+ with sqlite3.connect(self.db_path) as conn:
32
+ conn.execute("""
33
+ CREATE TABLE IF NOT EXISTS cache_store (
34
+ key TEXT PRIMARY KEY,
35
+ value TEXT NOT NULL,
36
+ epoch INTEGER NOT NULL,
37
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
38
+ );
39
+ """)
40
+ conn.execute("""
41
+ CREATE INDEX IF NOT EXISTS idx_cache_epoch
42
+ ON cache_store (epoch);
43
+ """)
44
+ conn.commit()
45
+
46
+ def get(self, key: str) -> Any | None:
47
+ """Retrieve a cached value.
48
+
49
+ Args:
50
+ key: Cache key.
51
+
52
+ Returns:
53
+ Cached value, or None if not found.
54
+ """
55
+ try:
56
+ with sqlite3.connect(self.db_path) as conn:
57
+ cursor = conn.execute(
58
+ "SELECT value FROM cache_store WHERE key = ?;",
59
+ (key,),
60
+ )
61
+ row = cursor.fetchone()
62
+ if row:
63
+ value_json = row[0]
64
+ return json.loads(value_json)
65
+ return None
66
+ except (sqlite3.DatabaseError, json.JSONDecodeError) as e:
67
+ logger.warning(f"Error retrieving cache key {key}: {e}", exc_info=True)
68
+ return None
69
+
70
+ def set(self, key: str, value: Any, epoch: int) -> None:
71
+ """Store a value with an associated epoch.
72
+
73
+ Args:
74
+ key: Cache key.
75
+ value: Value to cache.
76
+ epoch: Index epoch at cache time. Used for invalidation.
77
+ """
78
+ try:
79
+ value_json = json.dumps(value)
80
+ with sqlite3.connect(self.db_path) as conn:
81
+ conn.execute(
82
+ """
83
+ INSERT INTO cache_store (key, value, epoch)
84
+ VALUES (?, ?, ?)
85
+ ON CONFLICT (key) DO UPDATE SET
86
+ value = EXCLUDED.value,
87
+ epoch = EXCLUDED.epoch;
88
+ """,
89
+ (key, value_json, epoch),
90
+ )
91
+ conn.commit()
92
+ except (sqlite3.DatabaseError, TypeError):
93
+ logger.exception(f"Error storing cache key {key}")
94
+
95
+ def invalidate_epoch(self, epoch: int) -> None:
96
+ """Invalidate all entries from an epoch or earlier.
97
+
98
+ Args:
99
+ epoch: Entries with epoch <= this are discarded.
100
+ """
101
+ try:
102
+ with sqlite3.connect(self.db_path) as conn:
103
+ cursor = conn.execute(
104
+ "DELETE FROM cache_store WHERE epoch <= ?;",
105
+ (epoch,),
106
+ )
107
+ conn.commit()
108
+ logger.debug(
109
+ f"Invalidated cache entries for epochs <= {epoch} "
110
+ f"({cursor.rowcount} entries deleted)"
111
+ )
112
+ except sqlite3.DatabaseError:
113
+ logger.exception(f"Error invalidating cache epoch {epoch}")
@@ -0,0 +1,5 @@
1
+ """Embedding provider adapters implementing the EmbeddingProvider port."""
2
+
3
+ from searchkernel.adapters.embedding.huggingface import HuggingFaceEmbeddingProvider
4
+
5
+ __all__ = ["HuggingFaceEmbeddingProvider"]
@@ -0,0 +1,89 @@
1
+ """HuggingFace / sentence-transformers EmbeddingProvider adapter.
2
+
3
+ In-process embedding via ``sentence_transformers.SentenceTransformer``.
4
+ Defaults to Qwen3-Embedding-0.6B. No Ollama, no external service.
5
+
6
+ This is an ADDITIVE port implementation. The live embedding path
7
+ (``searchkernel/indices/vector.py``, BAAI/bge-small-en-v1.5) is untouched.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import TYPE_CHECKING
13
+
14
+ from searchkernel.domain import Vector
15
+
16
+ if TYPE_CHECKING:
17
+ from sentence_transformers import SentenceTransformer
18
+
19
+ # Documented Qwen3-Embedding query instruction, used only if the loaded model
20
+ # does not expose a "query" prompt via sentence-transformers.
21
+ _QWEN3_QUERY_INSTRUCTION = (
22
+ "Instruct: Given a web search query, retrieve relevant passages\nQuery: "
23
+ )
24
+
25
+
26
+ class HuggingFaceEmbeddingProvider:
27
+ """EmbeddingProvider backed by a sentence-transformers model.
28
+
29
+ Qwen3-Embedding is asymmetric: queries take an instruction prompt,
30
+ documents do not. ``embed`` embeds DOCUMENTS (no prompt); ``embed_query``
31
+ applies the query instruction. The EmbeddingProvider port itself has no
32
+ query variant yet -- that asymmetry lives here until W4a lifts it into
33
+ the port contract.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ model_name: str = "Qwen/Qwen3-Embedding-0.6B",
39
+ *,
40
+ truncate_dim: int | None = None,
41
+ device: str | None = None,
42
+ ):
43
+ from sentence_transformers import SentenceTransformer
44
+
45
+ self.model_name = model_name
46
+ self._truncate_dim = truncate_dim
47
+ # Matryoshka (MRL): passing truncate_dim makes the model emit
48
+ # truncated + re-normalized vectors directly.
49
+ self._model: SentenceTransformer = SentenceTransformer(
50
+ model_name, truncate_dim=truncate_dim, device=device
51
+ )
52
+ native_dim = self._model.get_sentence_embedding_dimension()
53
+ self.dim: int = truncate_dim if truncate_dim is not None else int(native_dim)
54
+ # Whether the model ships a named "query" prompt we can reference.
55
+ self._has_query_prompt = "query" in getattr(self._model, "prompts", {})
56
+
57
+ def embed(self, texts: list[str]) -> list[Vector]:
58
+ """Embed DOCUMENTS (no instruction prompt), L2-normalized."""
59
+ embeddings = self._model.encode(
60
+ texts,
61
+ batch_size=32,
62
+ normalize_embeddings=True,
63
+ convert_to_numpy=True,
64
+ )
65
+ return embeddings.tolist()
66
+
67
+ def embed_query(self, text: str) -> Vector:
68
+ """Embed a single QUERY with the Qwen3 instruction prompt applied."""
69
+ return self.embed_queries([text])[0]
70
+
71
+ def embed_queries(self, texts: list[str]) -> list[Vector]:
72
+ """Embed QUERIES with the Qwen3 instruction prompt applied."""
73
+ if self._has_query_prompt:
74
+ embeddings = self._model.encode(
75
+ texts,
76
+ prompt_name="query",
77
+ batch_size=32,
78
+ normalize_embeddings=True,
79
+ convert_to_numpy=True,
80
+ )
81
+ else:
82
+ embeddings = self._model.encode(
83
+ texts,
84
+ prompt=_QWEN3_QUERY_INSTRUCTION,
85
+ batch_size=32,
86
+ normalize_embeddings=True,
87
+ convert_to_numpy=True,
88
+ )
89
+ return embeddings.tolist()
@@ -0,0 +1,5 @@
1
+ """LLM provider adapters implementing the LLMProvider port."""
2
+
3
+ from searchkernel.adapters.llm.copilot import CopilotLLMProvider
4
+
5
+ __all__ = ["CopilotLLMProvider"]