claude-smart 0.2.42 → 0.2.43

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 (392) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +1 -1
  3. package/package.json +9 -3
  4. package/plugin/.claude-plugin/plugin.json +9 -3
  5. package/plugin/.codex-plugin/plugin.json +1 -1
  6. package/plugin/README.md +2 -2
  7. package/plugin/pyproject.toml +2 -2
  8. package/plugin/scripts/_lib.sh +91 -0
  9. package/plugin/scripts/backend-service.sh +1 -0
  10. package/plugin/scripts/cli.sh +1 -0
  11. package/plugin/scripts/codex-hook.js +72 -4
  12. package/plugin/scripts/dashboard-build.sh +1 -0
  13. package/plugin/scripts/dashboard-service.sh +1 -0
  14. package/plugin/scripts/hook_entry.sh +1 -0
  15. package/plugin/scripts/smart-install.sh +1 -0
  16. package/plugin/src/claude_smart/context_format.py +11 -12
  17. package/plugin/src/claude_smart/cs_cite.py +26 -12
  18. package/plugin/src/claude_smart/ids.py +13 -5
  19. package/plugin/uv.lock +1 -1
  20. package/plugin/vendor/reflexio/.env.example +53 -0
  21. package/plugin/vendor/reflexio/LICENSE +201 -0
  22. package/plugin/vendor/reflexio/README.md +338 -0
  23. package/plugin/vendor/reflexio/pyproject.toml +271 -0
  24. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  25. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  26. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  27. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  28. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  29. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  37. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  38. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  39. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  40. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +266 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +961 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  68. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  69. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  70. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  71. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  72. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  148. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  149. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  150. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  151. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  162. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  163. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  164. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  165. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  166. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1103 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +766 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +280 -0
  180. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  181. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  182. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  183. package/plugin/vendor/reflexio/reflexio/server/README.md +616 -0
  184. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  185. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  186. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  187. package/plugin/vendor/reflexio/reflexio/server/api.py +2714 -0
  188. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
  189. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
  190. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
  192. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +540 -0
  193. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
  194. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
  195. package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
  196. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
  197. package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
  198. package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
  199. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +110 -0
  200. package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
  201. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1595 -0
  202. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +112 -0
  203. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +469 -0
  204. package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
  205. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +210 -0
  208. package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
  209. package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +255 -0
  210. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
  211. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +177 -0
  212. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
  213. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +699 -0
  214. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
  215. package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
  216. package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
  217. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
  218. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
  219. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
  220. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
  221. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
  222. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
  223. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
  224. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
  225. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
  226. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
  227. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
  228. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
  229. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
  230. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
  231. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
  232. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
  233. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
  234. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
  235. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
  236. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
  237. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
  238. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
  239. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
  240. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
  241. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  242. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +279 -0
  243. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  244. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +127 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  277. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  278. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  279. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  281. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  282. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +340 -0
  283. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1626 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +351 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +468 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +777 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +91 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +689 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +960 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +741 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +734 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +800 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +70 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +671 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1253 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +372 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +568 -0
  380. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  381. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  382. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  383. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  384. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  385. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  386. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  387. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  388. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  389. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  390. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  391. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  392. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,255 @@
1
+ """Local in-process embedder using ``nomic-ai/nomic-embed-text-v1.5``.
2
+
3
+ A higher-quality alternative to the chromadb-bundled MiniLM-L6-v2: 137M
4
+ parameters, 768-dim native, supports Matryoshka representation (64–768
5
+ dimensions without retraining), 8192-token context, Apache-2.0 licensed.
6
+ Performs comparably to OpenAI's ``text-embedding-3-small`` on MTEB
7
+ retrieval at a fraction of the latency cost when run locally on CPU or
8
+ Apple Silicon.
9
+
10
+ Activation
11
+ ----------
12
+
13
+ - Set ``CLAUDE_SMART_USE_LOCAL_EMBEDDING=1`` in the process environment.
14
+ - Pass model name ``local/nomic-embed-v1.5`` (or ``local/nomic-embed-text-v1.5``)
15
+ to :func:`LiteLLMClient.get_embedding`/``get_embeddings``.
16
+ - Requires the ``sentence-transformers`` pip dependency.
17
+
18
+ Storage compatibility
19
+ ---------------------
20
+
21
+ Reflexio's vec0 tables expect 512-dim vectors (``EMBEDDING_DIMENSIONS``).
22
+ Nomic's native 768 dim is reduced via Matryoshka — slice the first 512
23
+ floats, then re-normalize to unit length so cosine similarity remains
24
+ comparable. Quality on retrieval tasks at 512 dim is ~95% of the full
25
+ 768 (per Nomic's own evaluation).
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import importlib.util
31
+ import logging
32
+ import math
33
+ import os
34
+ import threading
35
+ from typing import Any
36
+
37
+ _LOGGER = logging.getLogger(__name__)
38
+
39
+ _ENV_ENABLE = "CLAUDE_SMART_USE_LOCAL_EMBEDDING"
40
+ _ENV_PROVIDER = "REFLEXIO_EMBEDDING_PROVIDER"
41
+ _ENV_DAEMON = "REFLEXIO_EMBEDDING_DAEMON"
42
+ _MODEL_KEYS = {"local/nomic-embed-v1.5", "local/nomic-embed-text-v1.5"}
43
+ _HF_MODEL_NAME = "nomic-ai/nomic-embed-text-v1.5"
44
+
45
+ # Reflexio's vec0 schema dim. Nomic v1.5 outputs 768 natively; we slice
46
+ # to 512 (Matryoshka) and re-normalize.
47
+ _TARGET_DIM = 512
48
+ # Nomic v1.5 was trained with task-prefixed inputs; "search_document"
49
+ # vs "search_query" prefixes give better asymmetric retrieval. Reflexio's
50
+ # storage layer already passes a "search_document: " / "search_query: "
51
+ # prefix when calling _get_embedding(purpose=...), so we don't add another
52
+ # prefix here — the input arrives correctly tagged.
53
+ # The model has a 8192 token context window; we still cap chars
54
+ # defensively to avoid pathological multi-MB inputs.
55
+ _MAX_CHARS = 32_000
56
+
57
+
58
+ class NomicEmbedderError(RuntimeError):
59
+ """Raised when the Nomic embedder is requested but its deps are missing."""
60
+
61
+
62
+ class NomicEmbedder:
63
+ """Lazily-loaded singleton wrapping a sentence-transformers model.
64
+
65
+ Loading the underlying ``nomic-embed-text-v1.5`` model takes ~5–10 s on
66
+ first call (downloads ~550 MB on cold start, then cached under
67
+ ``~/.cache/huggingface/``). After that, embedding latency on CPU is
68
+ ~30–60 ms per single text and ~200 ms per batch of 32 (Apple M-series).
69
+ """
70
+
71
+ _instance: NomicEmbedder | None = None
72
+ _lock = threading.Lock()
73
+
74
+ def __init__(self) -> None:
75
+ self._model: Any | None = None
76
+ self._model_lock = threading.Lock()
77
+
78
+ @classmethod
79
+ def get(cls) -> NomicEmbedder:
80
+ """Return the process-wide singleton, constructing it on first use."""
81
+ if cls._instance is None:
82
+ with cls._lock:
83
+ if cls._instance is None:
84
+ cls._instance = cls()
85
+ return cls._instance
86
+
87
+ def _load(self) -> Any:
88
+ """Lazy-import sentence-transformers and load the Nomic model."""
89
+ if self._model is not None:
90
+ return self._model
91
+ with self._model_lock:
92
+ if self._model is not None:
93
+ return self._model
94
+ try:
95
+ from sentence_transformers import (
96
+ SentenceTransformer, # type: ignore[import-not-found]
97
+ )
98
+ except ImportError as exc:
99
+ raise NomicEmbedderError(
100
+ "sentence-transformers is required for the Nomic local "
101
+ "embedder. Install with `uv add sentence-transformers`."
102
+ ) from exc
103
+ _LOGGER.info(
104
+ "Loading Nomic embedding model %s — first call may download "
105
+ "~550 MB to ~/.cache/huggingface/",
106
+ _HF_MODEL_NAME,
107
+ )
108
+ # Force CPU device — MPS init has been observed to hang on some
109
+ # Apple Silicon + macOS combos for several minutes during model
110
+ # load. CPU is fast enough for our use case (137M params) and
111
+ # behaves predictably. Set NOMIC_EMBED_DEVICE=mps|cuda|cpu to
112
+ # override.
113
+ device = os.environ.get("NOMIC_EMBED_DEVICE", "cpu")
114
+ self._model = SentenceTransformer(
115
+ _HF_MODEL_NAME,
116
+ trust_remote_code=True, # Nomic v1.5 ships custom code
117
+ device=device,
118
+ )
119
+ _LOGGER.info(
120
+ "Nomic embedder ready (model=%s, target_dim=%d, native_dim=%d)",
121
+ _HF_MODEL_NAME,
122
+ _TARGET_DIM,
123
+ self._model.get_sentence_embedding_dimension(),
124
+ )
125
+ return self._model
126
+
127
+ def embed(self, texts: list[str]) -> list[list[float]]:
128
+ """Embed a batch of texts, returning ``_TARGET_DIM``-sized unit vectors.
129
+
130
+ Args:
131
+ texts: Inputs to encode. Each is char-truncated to ``_MAX_CHARS``
132
+ as a defensive cap; Nomic itself supports 8192 tokens.
133
+
134
+ Returns:
135
+ list[list[float]]: One vector per input, each exactly
136
+ ``_TARGET_DIM`` (512) floats and L2-normalised so cosine
137
+ similarity equals dot product.
138
+ """
139
+ model = self._load()
140
+ safe = [(t or "")[:_MAX_CHARS] for t in texts]
141
+ # show_progress_bar=False so server logs stay clean during ingest
142
+ # batches. convert_to_numpy=True returns a numpy ndarray; we slice
143
+ # and renormalise per-row before converting to plain Python lists.
144
+ raw = model.encode(safe, show_progress_bar=False, convert_to_numpy=True)
145
+ return [_truncate_and_renormalise(vec.tolist()) for vec in raw]
146
+
147
+
148
+ def _truncate_and_renormalise(vec: list[float]) -> list[float]:
149
+ """Slice to ``_TARGET_DIM`` and L2-renormalise for valid Matryoshka use.
150
+
151
+ Args:
152
+ vec (list[float]): Native-dim Nomic embedding (typically 768 floats,
153
+ already L2-unit on the full 768).
154
+
155
+ Returns:
156
+ list[float]: Exactly ``_TARGET_DIM`` floats, L2-normalised in the
157
+ truncated subspace so cosine similarity remains a valid metric.
158
+ Zero-padded if the input is shorter than ``_TARGET_DIM``.
159
+ """
160
+ if len(vec) >= _TARGET_DIM:
161
+ sliced = vec[:_TARGET_DIM]
162
+ else:
163
+ sliced = vec + [0.0] * (_TARGET_DIM - len(vec))
164
+ norm = math.sqrt(sum(x * x for x in sliced))
165
+ if norm <= 0:
166
+ return sliced
167
+ return [x / norm for x in sliced]
168
+
169
+
170
+ _REGISTERED = False
171
+
172
+
173
+ def register_if_enabled() -> bool:
174
+ """Make the Nomic embedder available when env + deps allow it.
175
+
176
+ Idempotent. Returns ``True`` when the embedder is usable after this
177
+ call. Routing happens via prefix-match on the model name in
178
+ ``LiteLLMClient.get_embedding(s)``.
179
+
180
+ Eagerly pre-warms the model in a daemon thread so the first request
181
+ doesn't pay the ~30 s cold-start cost. The thread is fire-and-forget;
182
+ callers either land mid-load (and block briefly) or after-load (and
183
+ proceed immediately).
184
+ """
185
+ global _REGISTERED
186
+ if _REGISTERED:
187
+ return True
188
+ if os.environ.get(_ENV_ENABLE) != "1":
189
+ return False
190
+ provider = os.environ.get(_ENV_PROVIDER, "").strip().lower()
191
+ if provider in {"local_service", "internal_service", "off"}:
192
+ _LOGGER.info(
193
+ "Nomic in-process prewarm skipped because %s=%s",
194
+ _ENV_PROVIDER,
195
+ provider,
196
+ )
197
+ return False
198
+ if not provider and os.environ.get(_ENV_DAEMON) != "1":
199
+ _LOGGER.info(
200
+ "Nomic in-process prewarm skipped; %s=1 now defaults to the "
201
+ "shared embedding service.",
202
+ _ENV_ENABLE,
203
+ )
204
+ return False
205
+ if importlib.util.find_spec("sentence_transformers") is None:
206
+ _LOGGER.warning(
207
+ "%s=1 set but `sentence-transformers` not installed; the Nomic "
208
+ "local embedder will not be available.",
209
+ _ENV_ENABLE,
210
+ )
211
+ return False
212
+ _REGISTERED = True
213
+ _LOGGER.info(
214
+ "Nomic local embedding provider enabled (models=%s)", sorted(_MODEL_KEYS)
215
+ )
216
+
217
+ def _prewarm() -> None:
218
+ """Background load + dummy inference so the first real request is fast."""
219
+ try:
220
+ embedder = NomicEmbedder.get()
221
+ embedder.embed(["warmup"])
222
+ _LOGGER.info("Nomic embedder pre-warmed")
223
+ except Exception: # noqa: BLE001
224
+ _LOGGER.exception(
225
+ "Nomic embedder pre-warm failed; first call will pay the cost"
226
+ )
227
+
228
+ threading.Thread(target=_prewarm, daemon=True, name="nomic-prewarm").start()
229
+ return True
230
+
231
+
232
+ def is_enabled() -> bool:
233
+ """Return True after a successful :func:`register_if_enabled`."""
234
+ return _REGISTERED
235
+
236
+
237
+ def is_nomic_model(model: str) -> bool:
238
+ """Predicate used by ``LiteLLMClient`` to route by model name.
239
+
240
+ Args:
241
+ model (str): The embedding model name passed by the caller.
242
+
243
+ Returns:
244
+ bool: True when the model resolves to the Nomic provider.
245
+ """
246
+ return model in _MODEL_KEYS
247
+
248
+
249
+ __all__ = [
250
+ "NomicEmbedder",
251
+ "NomicEmbedderError",
252
+ "is_enabled",
253
+ "is_nomic_model",
254
+ "register_if_enabled",
255
+ ]
@@ -0,0 +1,6 @@
1
+ """Reranking helpers — local cross-encoder + LLM relevance judge."""
2
+
3
+ from reflexio.server.llm.rerank.cross_encoder_reranker import prewarm, score_pairs
4
+ from reflexio.server.llm.rerank.llm_reranker import score_pairs_llm
5
+
6
+ __all__ = ["prewarm", "score_pairs", "score_pairs_llm"]
@@ -0,0 +1,177 @@
1
+ """Local cross-encoder reranker for ``(query, document)`` pairs.
2
+
3
+ Wraps ``cross-encoder/ms-marco-MiniLM-L-6-v2`` (~25M params) from
4
+ ``sentence-transformers``. The model is lazy-loaded on first call and
5
+ held as a process-wide singleton — load takes ~3 s but only happens
6
+ once per server start. Scoring K=30 pairs takes ~50 ms on CPU.
7
+
8
+ Usage
9
+ -----
10
+
11
+ >>> from reflexio.server.llm.rerank import score_pairs
12
+ >>> scores = score_pairs("italian food", ["pasta lover", "weather report"])
13
+ >>> scores[0] > scores[1]
14
+ True
15
+
16
+ The helper is intentionally side-effect free at import time: building
17
+ the singleton happens only when ``score_pairs`` is called, so importing
18
+ this module never triggers a model download.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ import threading
25
+ from typing import Any
26
+
27
+ _LOGGER = logging.getLogger(__name__)
28
+
29
+ # HuggingFace identifier for the cross-encoder. Chosen for the
30
+ # size/quality trade-off: 22M parameters, ~50 ms for K=30 on CPU,
31
+ # well-known MS-MARCO benchmark performance.
32
+ _MODEL_NAME = "cross-encoder/ms-marco-MiniLM-L-6-v2"
33
+
34
+ # Singleton state — never accessed directly outside ``_get_model``.
35
+ _MODEL: Any | None = None
36
+ _MODEL_LOCK = threading.Lock()
37
+
38
+
39
+ class CrossEncoderUnavailableError(RuntimeError):
40
+ """Raised when the cross-encoder model cannot be loaded.
41
+
42
+ The most common cause is ``sentence-transformers`` being absent from
43
+ the runtime environment. Callers should treat this as a soft failure
44
+ (log + skip rerank) rather than a 500.
45
+ """
46
+
47
+
48
+ def _import_cross_encoder() -> Any:
49
+ """Robustly import ``sentence_transformers.CrossEncoder``.
50
+
51
+ The ``sentence_transformers`` package is loaded both by the Nomic
52
+ local-embedding pre-warm thread (kicked off by ``LiteLLMClient.__init__``
53
+ when ``CLAUDE_SMART_USE_LOCAL_EMBEDDING=1``) and by this reranker. When
54
+ those concurrent imports race, one thread can see a half-loaded
55
+ ``sentence_transformers`` module in ``sys.modules`` whose ``CrossEncoder``
56
+ attribute was never bound — Python's import machinery hands back the
57
+ partial module without re-running ``__init__``. This helper detects that
58
+ case, drops the stale entry, and re-imports cleanly.
59
+
60
+ Returns:
61
+ Any: The ``CrossEncoder`` class.
62
+
63
+ Raises:
64
+ CrossEncoderUnavailableError: When the package genuinely isn't
65
+ installed, or every retry yields a partial module.
66
+ """
67
+ import sys
68
+
69
+ for _attempt in range(2):
70
+ try:
71
+ from sentence_transformers import CrossEncoder
72
+ except ImportError:
73
+ # Partial import — drop the stale entry and try once more.
74
+ sys.modules.pop("sentence_transformers", None)
75
+ continue
76
+ return CrossEncoder
77
+ try:
78
+ from sentence_transformers import (
79
+ CrossEncoder, # noqa: F401 — final attempt for the error path
80
+ )
81
+ except ImportError as e:
82
+ raise CrossEncoderUnavailableError(
83
+ "sentence-transformers is not installed; cannot use the "
84
+ "cross-encoder reranker"
85
+ ) from e
86
+ return CrossEncoder
87
+
88
+
89
+ def _get_model() -> Any:
90
+ """Return the lazy-loaded cross-encoder singleton.
91
+
92
+ The first caller pays the load cost (~3 s, weights cached under
93
+ ``~/.cache/huggingface/`` after first download). Subsequent callers
94
+ get the warm instance immediately.
95
+
96
+ Returns:
97
+ Any: A ``sentence_transformers.CrossEncoder`` instance.
98
+
99
+ Raises:
100
+ CrossEncoderUnavailableError: If ``sentence-transformers`` is not
101
+ importable, or if the underlying model fails to load.
102
+ """
103
+ global _MODEL # noqa: PLW0603 — singleton-pattern intentional
104
+ if _MODEL is not None:
105
+ return _MODEL
106
+ with _MODEL_LOCK:
107
+ if _MODEL is not None:
108
+ return _MODEL
109
+ cross_encoder_cls = _import_cross_encoder()
110
+ try:
111
+ _MODEL = cross_encoder_cls(_MODEL_NAME)
112
+ except Exception as e: # noqa: BLE001 — surface as a typed failure
113
+ raise CrossEncoderUnavailableError(
114
+ f"Failed to load cross-encoder model {_MODEL_NAME!r}: {e}"
115
+ ) from e
116
+ _LOGGER.info("Loaded cross-encoder model %s", _MODEL_NAME)
117
+ return _MODEL
118
+
119
+
120
+ def score_pairs(query: str, docs: list[str]) -> list[float]:
121
+ """Score ``(query, doc)`` pairs with the cross-encoder.
122
+
123
+ Higher score means more relevant. Scores are not bounded to a fixed
124
+ range — they are raw model logits — so callers should treat them as
125
+ opaque relative-ranking signal, not as probabilities.
126
+
127
+ Args:
128
+ query (str): The reranking query.
129
+ docs (list[str]): Documents to score against ``query``.
130
+
131
+ Returns:
132
+ list[float]: One score per document, in the same order as
133
+ ``docs``. Empty list when ``docs`` is empty.
134
+
135
+ Raises:
136
+ CrossEncoderUnavailableError: If the cross-encoder cannot be
137
+ loaded (re-raised from :func:`_get_model`).
138
+ """
139
+ if not docs:
140
+ return []
141
+ model = _get_model()
142
+ pairs = [(query, doc) for doc in docs]
143
+ raw_scores = model.predict(pairs)
144
+ # ``predict`` returns a numpy array; convert to plain Python floats so
145
+ # the caller can serialise the result without numpy as a dependency.
146
+ return [float(s) for s in raw_scores]
147
+
148
+
149
+ def prewarm() -> bool:
150
+ """Force the cross-encoder model to load at startup.
151
+
152
+ Call once during app startup so the ~3s model load never lands on a user
153
+ query (and never serializes a concurrent burst behind the model lock).
154
+ Never raises — startup must not crash if the cross-encoder is unavailable
155
+ or fails to score the smoke input.
156
+
157
+ Returns:
158
+ True if the model loaded and scored a smoke input; False otherwise
159
+ (callers should treat the floor as degraded, not crash).
160
+ """
161
+ try:
162
+ score_pairs("warmup", ["warmup"])
163
+ except CrossEncoderUnavailableError:
164
+ _LOGGER.warning(
165
+ "Cross-encoder unavailable at startup; relevance floor will degrade "
166
+ "to unfiltered results until the model is available."
167
+ )
168
+ return False
169
+ except Exception: # noqa: BLE001 — pre-warm must never crash startup
170
+ _LOGGER.warning(
171
+ "Cross-encoder pre-warm failed unexpectedly; relevance floor will "
172
+ "degrade to unfiltered results until the model is available.",
173
+ exc_info=True,
174
+ )
175
+ return False
176
+ _LOGGER.info("Cross-encoder pre-warmed.")
177
+ return True
@@ -0,0 +1,148 @@
1
+ """LLM-based reranker for ``(query, document)`` pairs.
2
+
3
+ Sends a single LLM call with the query and a numbered list of candidate
4
+ facts, expects a JSON array of relevance scores (0-10) in the same order.
5
+ Fills the gap that cross-encoders can't bridge: world knowledge / brand
6
+ ↔ category equivalence (e.g. "Thrive Market" = grocery service).
7
+
8
+ Usage
9
+ -----
10
+
11
+ >>> from reflexio.server.llm.rerank.llm_reranker import score_pairs_llm
12
+ >>> scores = score_pairs_llm(
13
+ ... query="grocery store",
14
+ ... docs=["Walmart $120 grocery", "Thrive Market organic"],
15
+ ... llm_client=client, prompt_manager=pm,
16
+ ... )
17
+ >>> # scores is a list[float] of length 2, or None on failure.
18
+
19
+ The helper returns ``None`` on any failure (no LLM client, prompt error,
20
+ LLM call error, malformed JSON, score-count mismatch). Callers should
21
+ fall back to the existing rerank order.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import logging
28
+ import re
29
+ from typing import Any
30
+
31
+ _LOGGER = logging.getLogger(__name__)
32
+
33
+ _PROMPT_ID = "rerank_relevance"
34
+ _LLM_TIMEOUT = 30.0
35
+ _LLM_MAX_RETRIES = 1
36
+
37
+
38
+ def _parse_scores(text: str, expected_n: int) -> list[float] | None:
39
+ """Extract a JSON array of N numbers from raw LLM output.
40
+
41
+ Tolerates surrounding prose by locating the outermost ``[ ... ]`` span
42
+ via the first ``[`` and last ``]``. Returns ``None`` when the array
43
+ can't be parsed or the count doesn't match ``expected_n``.
44
+
45
+ Args:
46
+ text (str): Raw LLM response.
47
+ expected_n (int): Number of scores expected.
48
+
49
+ Returns:
50
+ list[float] | None: Parsed scores, or ``None`` on any parse failure.
51
+ """
52
+ start = text.find("[")
53
+ end = text.rfind("]")
54
+ if start == -1 or end <= start:
55
+ return None
56
+ try:
57
+ parsed = json.loads(text[start : end + 1])
58
+ except json.JSONDecodeError:
59
+ return None
60
+ if not isinstance(parsed, list) or len(parsed) != expected_n:
61
+ return None
62
+ try:
63
+ return [float(s) for s in parsed]
64
+ except (TypeError, ValueError):
65
+ return None
66
+
67
+
68
+ def _format_docs_block(docs: list[str]) -> str:
69
+ """Render docs as a numbered, single-line-per-fact block.
70
+
71
+ Newlines inside individual docs are replaced with spaces so the LLM
72
+ sees a clean ``i. <fact>`` structure that matches the prompt's
73
+ output rule (one score per numbered fact).
74
+
75
+ Args:
76
+ docs (list[str]): Candidate documents.
77
+
78
+ Returns:
79
+ str: One ``i. <doc>`` per line.
80
+ """
81
+ flattened = (re.sub(r"\s+", " ", d).strip() for d in docs)
82
+ return "\n".join(f"{i + 1}. {d}" for i, d in enumerate(flattened))
83
+
84
+
85
+ def score_pairs_llm(
86
+ query: str,
87
+ docs: list[str],
88
+ llm_client: Any,
89
+ prompt_manager: Any,
90
+ timeout: float = _LLM_TIMEOUT,
91
+ ) -> list[float] | None:
92
+ """Score ``(query, doc)`` pairs via an LLM relevance-judge prompt.
93
+
94
+ A single LLM call is made for the entire batch; the model returns one
95
+ score per doc. The model is the LiteLLMClient's default — same model
96
+ that drives the search agent — chosen to keep configuration simple.
97
+
98
+ Args:
99
+ query (str): The reranking query.
100
+ docs (list[str]): Documents to score against ``query``.
101
+ llm_client (Any): A ``LiteLLMClient`` (must expose ``generate_response``).
102
+ prompt_manager (Any): A ``PromptManager`` (must expose ``render_prompt``).
103
+ timeout (float): Per-call timeout in seconds.
104
+
105
+ Returns:
106
+ list[float] | None: One score per doc on success (same order as
107
+ ``docs``); ``None`` on any failure so the caller can fall back.
108
+ """
109
+ if not docs:
110
+ return []
111
+ if llm_client is None or prompt_manager is None:
112
+ return None
113
+ try:
114
+ prompt = prompt_manager.render_prompt(
115
+ _PROMPT_ID,
116
+ {
117
+ "query": query,
118
+ "docs_block": _format_docs_block(docs),
119
+ "num_docs": str(len(docs)),
120
+ },
121
+ )
122
+ except Exception as e: # noqa: BLE001 — prompt-render failure must not break search
123
+ _LOGGER.warning("LLM rerank: prompt render failed: %s", e)
124
+ return None
125
+
126
+ try:
127
+ result = llm_client.generate_response(
128
+ prompt,
129
+ timeout=timeout,
130
+ max_retries=_LLM_MAX_RETRIES,
131
+ temperature=0.0,
132
+ )
133
+ except Exception as e: # noqa: BLE001 — LLM-call failure must not break search
134
+ _LOGGER.warning("LLM rerank: generate_response failed: %s", e)
135
+ return None
136
+
137
+ if not isinstance(result, str) or not result.strip():
138
+ _LOGGER.warning(
139
+ "LLM rerank: empty/non-string response (%r)", type(result).__name__
140
+ )
141
+ return None
142
+
143
+ scores = _parse_scores(result, expected_n=len(docs))
144
+ if scores is None:
145
+ _LOGGER.warning(
146
+ "LLM rerank: parse failure (n=%d, raw[:200]=%r)", len(docs), result[:200]
147
+ )
148
+ return scores