claude-smart 0.2.42 → 0.2.44

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 (402) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +1 -1
  3. package/bin/claude-smart.js +2 -2
  4. package/package.json +9 -3
  5. package/plugin/.claude-plugin/plugin.json +9 -3
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +23 -3
  8. package/plugin/pyproject.toml +3 -3
  9. package/plugin/scripts/_lib.sh +91 -0
  10. package/plugin/scripts/backend-service.sh +51 -4
  11. package/plugin/scripts/cli.sh +3 -1
  12. package/plugin/scripts/codex-hook.js +72 -4
  13. package/plugin/scripts/dashboard-build.sh +1 -0
  14. package/plugin/scripts/dashboard-service.sh +1 -0
  15. package/plugin/scripts/ensure-plugin-root.sh +1 -0
  16. package/plugin/scripts/hook_entry.sh +6 -3
  17. package/plugin/scripts/smart-install.sh +3 -2
  18. package/plugin/src/README.md +57 -0
  19. package/plugin/src/claude_smart/context_format.py +11 -12
  20. package/plugin/src/claude_smart/cs_cite.py +26 -12
  21. package/plugin/src/claude_smart/ids.py +13 -5
  22. package/plugin/uv.lock +126 -5
  23. package/plugin/vendor/reflexio/.env.example +62 -0
  24. package/plugin/vendor/reflexio/LICENSE +201 -0
  25. package/plugin/vendor/reflexio/README.md +338 -0
  26. package/plugin/vendor/reflexio/pyproject.toml +274 -0
  27. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  28. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  29. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  37. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  38. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  39. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  40. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +265 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +964 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  68. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  69. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  70. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  71. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  72. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  73. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  74. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  75. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  148. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  149. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  150. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  151. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  162. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  163. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  164. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  165. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  166. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1112 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +768 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  180. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  181. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  182. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +333 -0
  183. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  184. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  185. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  186. package/plugin/vendor/reflexio/reflexio/server/README.md +622 -0
  187. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  188. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  189. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  190. package/plugin/vendor/reflexio/reflexio/server/api.py +2868 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +34 -0
  192. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
  193. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
  194. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
  195. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
  196. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +562 -0
  197. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
  198. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
  199. package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
  200. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
  201. package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
  202. package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
  203. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +359 -0
  204. package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
  205. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1871 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +140 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +479 -0
  208. package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
  209. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
  210. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
  211. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +338 -0
  212. package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
  213. package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +288 -0
  214. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
  215. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +187 -0
  216. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
  217. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +716 -0
  218. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
  219. package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
  220. package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
  221. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
  222. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
  223. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
  224. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
  225. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
  226. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
  227. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
  228. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
  229. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
  230. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
  231. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
  232. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
  233. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
  234. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
  235. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
  236. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
  237. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
  238. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
  239. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
  240. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
  241. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
  242. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
  243. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
  244. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.1.prompt.md +69 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +71 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +283 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.2.prompt.md +234 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +244 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +137 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  276. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  277. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  278. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  279. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  280. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  281. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  282. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  283. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/README.md +58 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +336 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1668 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/embedding_text.py +62 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +358 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +535 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +779 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +94 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +702 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +1045 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +772 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +737 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +803 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +80 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +756 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1298 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +384 -0
  380. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  381. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  382. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  383. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  384. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  385. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  386. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  387. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  388. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  389. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +572 -0
  390. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  391. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  392. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  393. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  394. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  395. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  396. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  397. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  398. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  399. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  400. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  401. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  402. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,15 @@
1
+ """Reflexio caching module."""
2
+
3
+ from reflexio.server.cache.reflexio_cache import (
4
+ clear_reflexio_cache,
5
+ get_cache_stats,
6
+ get_reflexio,
7
+ invalidate_reflexio_cache,
8
+ )
9
+
10
+ __all__ = [
11
+ "get_reflexio",
12
+ "invalidate_reflexio_cache",
13
+ "clear_reflexio_cache",
14
+ "get_cache_stats",
15
+ ]
@@ -0,0 +1,208 @@
1
+ """Reflexio instance cache with explicit invalidation and version-based auto-eviction."""
2
+
3
+ import logging
4
+ import threading
5
+ from dataclasses import dataclass
6
+ from typing import Any, Final
7
+
8
+ from cachetools import TTLCache
9
+
10
+ from reflexio.lib.reflexio_lib import Reflexio
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # Cache configuration
15
+ REFLEXIO_CACHE_MAX_SIZE = 100
16
+ REFLEXIO_CACHE_TTL_SECONDS = 3600 # 1 hour safety net
17
+
18
+ # Type alias for cache key: (org_id, storage_base_dir)
19
+ CacheKey = tuple[str, str | None]
20
+
21
+
22
+ # Sentinel returned by ``_probe_version_safe`` when the underlying probe
23
+ # raised an exception. Distinguishing "probe failed transiently" from
24
+ # "backend can't probe" matters: the former should NOT promote the entry
25
+ # to permanent unprobeable state, otherwise a single transient error
26
+ # (e.g. brief Postgres reconnect, file lock contention) would silently
27
+ # disable version-based auto-eviction for the lifetime of the entry.
28
+ _PROBE_FAILED: Final = object()
29
+
30
+ # Type alias for ``current_config_version()`` return values plus our
31
+ # private sentinel. ``None`` means "backend doesn't support probing"
32
+ # (permanent), the sentinel means "probe raised this time" (transient).
33
+ _ProbeResult = tuple[str, Any] | None | object
34
+
35
+
36
+ @dataclass
37
+ class _CacheEntry:
38
+ """Per-org cache entry pairing a Reflexio instance with the config version stamped at load time.
39
+
40
+ The ``cached_version`` is whatever ``Reflexio.current_config_version()``
41
+ returned when the instance was constructed. On each cache hit we
42
+ re-probe and evict the entry if the value changed — this catches
43
+ out-of-band config mutations (file edits, sibling-replica writes,
44
+ direct DB updates) that don't go through ``invalidate_reflexio_cache``.
45
+
46
+ Attributes:
47
+ reflexio (Reflexio): The cached Reflexio instance.
48
+ cached_version (tuple[str, Any] | None): The version stamp
49
+ captured at load time. ``None`` means "no probe available";
50
+ entries with ``None`` are never auto-evicted (they fall
51
+ through to the TTL safety net). Probe failures during
52
+ construction never produce ``None`` here — they're recorded
53
+ as the same value the next probe attempt would compare
54
+ against, so a later successful probe can still evict the
55
+ stale entry.
56
+ """
57
+
58
+ reflexio: Reflexio
59
+ cached_version: tuple[str, Any] | None
60
+
61
+
62
+ # Module-level cache and lock
63
+ _reflexio_cache: TTLCache = TTLCache(
64
+ maxsize=REFLEXIO_CACHE_MAX_SIZE, ttl=REFLEXIO_CACHE_TTL_SECONDS
65
+ )
66
+ _reflexio_cache_lock = threading.Lock()
67
+
68
+
69
+ def _probe_version_safe(reflexio: Reflexio) -> _ProbeResult:
70
+ """Probe the current config version, distinguishing failure from "no probe".
71
+
72
+ A failing probe must never break a cache hit, but it also must not
73
+ be conflated with a backend that legitimately can't probe (which
74
+ returns ``None``). Conflating the two would let a single transient
75
+ failure permanently disable auto-eviction for the entry.
76
+
77
+ Args:
78
+ reflexio (Reflexio): The cached Reflexio instance to probe.
79
+
80
+ Returns:
81
+ ``tuple[str, Any]`` on success, ``None`` when the backend
82
+ intentionally doesn't expose a version (permanent), or the
83
+ ``_PROBE_FAILED`` sentinel when the call raised (transient).
84
+ """
85
+ try:
86
+ return reflexio.current_config_version()
87
+ except Exception as exc: # noqa: BLE001 - intentional broad catch
88
+ logger.warning(
89
+ "Failed to probe config version for org %s: %s — keeping entry warm",
90
+ reflexio.org_id,
91
+ exc,
92
+ )
93
+ return _PROBE_FAILED
94
+
95
+
96
+ def get_reflexio(org_id: str, storage_base_dir: str | None = None) -> Reflexio:
97
+ """Get or create a cached Reflexio instance.
98
+
99
+ On cache hit, the entry's stamped config version is re-probed. If
100
+ the persisted version has changed (e.g. config file mtime bumped,
101
+ sibling replica wrote new DB version), the entry is evicted and a
102
+ fresh instance is constructed.
103
+
104
+ Args:
105
+ org_id (str): Organization ID
106
+ storage_base_dir (Optional[str]): Base directory for storage (self-host mode)
107
+
108
+ Returns:
109
+ Reflexio: Cached or newly created instance
110
+ """
111
+ cache_key: CacheKey = (org_id, storage_base_dir)
112
+
113
+ # Cache lookup — held briefly to extract the entry, then released
114
+ # before doing any I/O (file stat, DB query) for the version probe.
115
+ with _reflexio_cache_lock:
116
+ entry: _CacheEntry | None = _reflexio_cache.get(cache_key)
117
+
118
+ if entry is not None:
119
+ cached_version = entry.cached_version
120
+ # Skip probing when we have nothing to compare against — a
121
+ # ``None`` stamp means the backend can't probe cheaply, so we
122
+ # rely on TTL + explicit invalidation instead.
123
+ if cached_version is None:
124
+ return entry.reflexio
125
+ current_version = _probe_version_safe(entry.reflexio)
126
+ # Transient probe failure: keep the cached instance for this
127
+ # request but DON'T mutate the stamp — the next request will
128
+ # try again, so a brief outage doesn't permanently disable
129
+ # eviction the way collapsing failures into ``None`` would.
130
+ if current_version is _PROBE_FAILED:
131
+ return entry.reflexio
132
+ if current_version == cached_version:
133
+ return entry.reflexio
134
+ # Stale entry. Evict only if the cached version still matches
135
+ # the one we just compared against — another thread may have
136
+ # already replaced the entry while we were probing.
137
+ with _reflexio_cache_lock:
138
+ existing = _reflexio_cache.get(cache_key)
139
+ if existing is not None and existing.cached_version == cached_version:
140
+ del _reflexio_cache[cache_key]
141
+
142
+ # Cache miss (or just-evicted stale entry) - create a new instance
143
+ # outside the lock to avoid blocking concurrent requests for other orgs.
144
+ reflexio = Reflexio(org_id=org_id, storage_base_dir=storage_base_dir)
145
+ new_version = _probe_version_safe(reflexio)
146
+
147
+ # Construction-time probe failure: serve this request from the
148
+ # newly-built instance but DON'T cache it. Caching with
149
+ # ``cached_version=None`` would conflate the entry with a
150
+ # legitimately-unprobeable backend and permanently disable
151
+ # auto-eviction. Skipping the cache means the next request pays a
152
+ # construction cost, but version-based eviction is preserved as
153
+ # soon as the backend recovers.
154
+ if new_version is _PROBE_FAILED:
155
+ return reflexio
156
+
157
+ new_entry = _CacheEntry(
158
+ reflexio=reflexio,
159
+ cached_version=new_version, # type: ignore[arg-type]
160
+ )
161
+
162
+ with _reflexio_cache_lock:
163
+ # Double-check in case another thread populated while we were constructing.
164
+ existing = _reflexio_cache.get(cache_key)
165
+ if existing is None:
166
+ _reflexio_cache[cache_key] = new_entry
167
+ return reflexio
168
+ return existing.reflexio
169
+
170
+
171
+ def invalidate_reflexio_cache(org_id: str, storage_base_dir: str | None = None) -> bool:
172
+ """Invalidate cached Reflexio for specific org.
173
+
174
+ Call this after set_config to ensure next request gets fresh instance.
175
+
176
+ Args:
177
+ org_id (str): Organization ID to invalidate
178
+ storage_base_dir (Optional[str]): Base directory for storage
179
+
180
+ Returns:
181
+ bool: True if entry was removed, False if not found
182
+ """
183
+ cache_key: CacheKey = (org_id, storage_base_dir)
184
+ with _reflexio_cache_lock:
185
+ if cache_key in _reflexio_cache:
186
+ del _reflexio_cache[cache_key]
187
+ return True
188
+ return False
189
+
190
+
191
+ def clear_reflexio_cache() -> None:
192
+ """Clear entire cache (for testing/admin)."""
193
+ with _reflexio_cache_lock:
194
+ _reflexio_cache.clear()
195
+
196
+
197
+ def get_cache_stats() -> dict:
198
+ """Get cache statistics for monitoring.
199
+
200
+ Returns:
201
+ dict: Cache statistics including current size, max size, and TTL
202
+ """
203
+ with _reflexio_cache_lock:
204
+ return {
205
+ "current_size": len(_reflexio_cache),
206
+ "max_size": REFLEXIO_CACHE_MAX_SIZE,
207
+ "ttl_seconds": REFLEXIO_CACHE_TTL_SECONDS,
208
+ }
@@ -0,0 +1,46 @@
1
+ """Request correlation ID for tracing concurrent operations.
2
+
3
+ Stores a short hex ID in a ContextVar so every log line emitted during a
4
+ single HTTP request (including ThreadPoolExecutor worker threads) can be
5
+ correlated back to the originating request.
6
+
7
+ Usage in worker threads::
8
+
9
+ ctx = contextvars.copy_context()
10
+ executor.submit(ctx.run, fn, *args)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import contextvars
16
+ import logging
17
+ import uuid
18
+
19
+ # ContextVar holds the correlation ID for the current request.
20
+ # Default is empty string (non-request contexts like startup, CLI).
21
+ correlation_id_var: contextvars.ContextVar[str] = contextvars.ContextVar(
22
+ "correlation_id", default=""
23
+ )
24
+
25
+
26
+ def generate_correlation_id() -> str:
27
+ """Generate a short 8-character hex correlation ID."""
28
+ return uuid.uuid4().hex[:8]
29
+
30
+
31
+ class CorrelationIdFilter(logging.Filter):
32
+ """Logging filter that injects correlation fields into every log record.
33
+
34
+ Attach this filter to handlers so formatters can use:
35
+
36
+ - ``%(correlation_id)s`` — the raw ID (empty string outside request context).
37
+ - ``%(correlation_tag)s`` — a ready-to-embed ``"[<cid>] "`` string that
38
+ collapses to ``""`` when there is no correlation ID. Use this in format
39
+ strings to avoid rendering an empty ``[]`` at startup / CLI time.
40
+ """
41
+
42
+ def filter(self, record: logging.LogRecord) -> bool:
43
+ cid = correlation_id_var.get("")
44
+ record.correlation_id = cid # type: ignore[attr-defined]
45
+ record.correlation_tag = f"[{cid}] " if cid else "" # type: ignore[attr-defined]
46
+ return True
@@ -0,0 +1,30 @@
1
+ """
2
+ LLM client package providing unified access to multiple LLM providers.
3
+
4
+ This package uses LiteLLM as the backend to provide a consistent interface
5
+ for OpenAI, Claude, Azure OpenAI, and other LLM providers.
6
+ """
7
+
8
+ from .litellm_client import (
9
+ LiteLLMClient,
10
+ LiteLLMClientError,
11
+ LiteLLMConfig,
12
+ ToolCallingChatResponse,
13
+ create_litellm_client,
14
+ )
15
+ from .model_defaults import (
16
+ ModelRole,
17
+ resolve_model_name,
18
+ validate_llm_availability,
19
+ )
20
+
21
+ __all__ = [
22
+ "LiteLLMClient",
23
+ "LiteLLMConfig",
24
+ "LiteLLMClientError",
25
+ "ModelRole",
26
+ "ToolCallingChatResponse",
27
+ "create_litellm_client",
28
+ "resolve_model_name",
29
+ "validate_llm_availability",
30
+ ]
@@ -0,0 +1,359 @@
1
+ """OpenAI-compatible local embedding service."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import math
7
+ import os
8
+ import threading
9
+ import time
10
+ from collections.abc import AsyncIterator
11
+ from contextlib import asynccontextmanager
12
+ from dataclasses import dataclass, field
13
+ from typing import Any
14
+
15
+ from fastapi import FastAPI, HTTPException
16
+ from pydantic import BaseModel, Field
17
+
18
+ from reflexio.server.llm.llm_utils import positive_int_env
19
+ from reflexio.server.llm.providers.local_embedding_provider import LocalEmbedder
20
+ from reflexio.server.llm.providers.nomic_embedding_provider import (
21
+ NomicEmbedder,
22
+ is_nomic_model,
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ MINILM_MODEL = "local/minilm-l6-v2"
28
+ NOMIC_TEXT_MODEL = "local/nomic-embed-text-v1.5"
29
+ _SUPPORTED_MODELS = {
30
+ MINILM_MODEL,
31
+ "local/nomic-embed-v1.5",
32
+ NOMIC_TEXT_MODEL,
33
+ }
34
+ _ACTIVE_MODEL: str | None = None
35
+ _ACTIVE_MODEL_LOCK = threading.Lock()
36
+
37
+ DEFAULT_OSS_EMBEDDING_MODEL = MINILM_MODEL
38
+
39
+ # Bound how many embed/encode calls run at once. The endpoint is a sync ``def``
40
+ # served from Starlette's threadpool, so without a guard a burst of requests
41
+ # would run that many model.encode() calls in parallel, stacking their
42
+ # activation memory and OOM-killing the daemon. The semaphore caps simultaneous
43
+ # encodes; excess requests block on acquire() and are picked up when a slot
44
+ # frees — they queue, they are never rejected. Pair with a small encode
45
+ # batch_size so each in-flight encode stays cheap.
46
+ _DEFAULT_MAX_CONCURRENCY = 4
47
+ _ENV_MAX_CONCURRENCY = "REFLEXIO_EMBED_MAX_CONCURRENCY"
48
+ _ENCODE_SEMAPHORE: threading.BoundedSemaphore | None = None
49
+ _ENCODE_SEMAPHORE_LOCK = threading.Lock()
50
+
51
+ # Opportunistically coalesce concurrent small requests before calling
52
+ # model.encode(). This keeps request concurrency thread-based while giving the
53
+ # GPU larger batches during bursts.
54
+ _DEFAULT_MICRO_BATCH_DELAY_MS = 5
55
+ _DEFAULT_MICRO_BATCH_MAX_TEXTS = 64
56
+ _ENV_MICRO_BATCH_DELAY_MS = "REFLEXIO_EMBED_MICRO_BATCH_DELAY_MS"
57
+ _ENV_MICRO_BATCH_MAX_TEXTS = "REFLEXIO_EMBED_MICRO_BATCH_MAX_TEXTS"
58
+ _MICRO_BATCH_CONDITION = threading.Condition()
59
+ _MICRO_BATCH_QUEUE: list[_EmbeddingJob] = []
60
+ _ACTIVE_BATCH_PROCESSORS = 0
61
+ # Failsafe bound for a submitter waiting on its job (see _embed_texts).
62
+ _JOB_WAIT_TIMEOUT_SECONDS = 600.0
63
+
64
+
65
+ @dataclass
66
+ class _EmbeddingJob:
67
+ model: str
68
+ texts: list[str]
69
+ done: threading.Event = field(default_factory=threading.Event)
70
+ result: list[list[float]] | None = None
71
+ error: BaseException | None = None
72
+
73
+
74
+ def _nonnegative_int_env(name: str, default: int) -> int:
75
+ raw = os.environ.get(name)
76
+ if not raw:
77
+ return default
78
+ try:
79
+ value = int(raw)
80
+ except ValueError:
81
+ logger.warning("Invalid %s=%r; falling back to default %d", name, raw, default)
82
+ return default
83
+ return value if value >= 0 else default
84
+
85
+
86
+ def _max_concurrency() -> int:
87
+ """Resolve the max simultaneous encodes from env, defaulting to 4."""
88
+ return positive_int_env(_ENV_MAX_CONCURRENCY, _DEFAULT_MAX_CONCURRENCY, logger)
89
+
90
+
91
+ def _micro_batch_delay_seconds() -> float:
92
+ return (
93
+ _nonnegative_int_env(_ENV_MICRO_BATCH_DELAY_MS, _DEFAULT_MICRO_BATCH_DELAY_MS)
94
+ / 1000
95
+ )
96
+
97
+
98
+ def _micro_batch_max_texts() -> int:
99
+ return positive_int_env(
100
+ _ENV_MICRO_BATCH_MAX_TEXTS, _DEFAULT_MICRO_BATCH_MAX_TEXTS, logger
101
+ )
102
+
103
+
104
+ def _encode_semaphore() -> threading.BoundedSemaphore:
105
+ """Return the process-wide encode semaphore, building it on first use."""
106
+ global _ENCODE_SEMAPHORE
107
+ if _ENCODE_SEMAPHORE is None:
108
+ with _ENCODE_SEMAPHORE_LOCK:
109
+ if _ENCODE_SEMAPHORE is None:
110
+ _ENCODE_SEMAPHORE = threading.BoundedSemaphore(_max_concurrency())
111
+ return _ENCODE_SEMAPHORE
112
+
113
+
114
+ class EmbeddingRequest(BaseModel):
115
+ model: str
116
+ input: str | list[str]
117
+ dimensions: int | None = Field(default=None, gt=0)
118
+
119
+
120
+ class EmbeddingData(BaseModel):
121
+ object: str = "embedding"
122
+ embedding: list[float]
123
+ index: int
124
+
125
+
126
+ class EmbeddingResponse(BaseModel):
127
+ object: str = "list"
128
+ data: list[EmbeddingData]
129
+ model: str
130
+
131
+
132
+ def create_embedding_app(default_model: str | None = None) -> FastAPI:
133
+ """Create the embedding daemon app and optionally warm a default model."""
134
+
135
+ @asynccontextmanager
136
+ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
137
+ if not default_model:
138
+ yield
139
+ return
140
+ try:
141
+ _embed_texts(default_model, ["reflexio embedding daemon warmup"])
142
+ except Exception:
143
+ logger.exception("Failed to warm embedding model %s", default_model)
144
+ raise
145
+ yield
146
+
147
+ embedding_app = FastAPI(title="Reflexio Embedding Service", lifespan=lifespan)
148
+
149
+ @embedding_app.get("/health")
150
+ def health() -> dict[str, Any]:
151
+ """Health check endpoint."""
152
+ return {"status": "ok", "active_model": _ACTIVE_MODEL}
153
+
154
+ @embedding_app.post("/v1/embeddings")
155
+ def create_embeddings(request: EmbeddingRequest) -> EmbeddingResponse:
156
+ """Create embeddings using the daemon's single active local model."""
157
+ texts = (
158
+ [request.input] if isinstance(request.input, str) else list(request.input)
159
+ )
160
+ embeddings = _embed_texts(request.model, texts)
161
+
162
+ if request.dimensions:
163
+ embeddings = [
164
+ _resize_embedding(vec, request.dimensions) for vec in embeddings
165
+ ]
166
+
167
+ return EmbeddingResponse(
168
+ data=[
169
+ EmbeddingData(embedding=embedding, index=index)
170
+ for index, embedding in enumerate(embeddings)
171
+ ],
172
+ model=request.model,
173
+ )
174
+
175
+ return embedding_app
176
+
177
+
178
+ def _embed_texts(model: str, texts: list[str]) -> list[list[float]]:
179
+ _activate_model(model)
180
+ if not texts:
181
+ return []
182
+
183
+ job = _EmbeddingJob(model=model, texts=list(texts))
184
+ should_process = False
185
+
186
+ global _ACTIVE_BATCH_PROCESSORS
187
+ with _MICRO_BATCH_CONDITION:
188
+ _MICRO_BATCH_QUEUE.append(job)
189
+ if _max_concurrency() > _ACTIVE_BATCH_PROCESSORS:
190
+ _ACTIVE_BATCH_PROCESSORS += 1
191
+ should_process = True
192
+ _MICRO_BATCH_CONDITION.notify()
193
+
194
+ if should_process:
195
+ threading.Thread(
196
+ target=_run_micro_batch_processor,
197
+ daemon=True,
198
+ name="embedding-micro-batch",
199
+ ).start()
200
+
201
+ # Last-resort failsafe: a processor thread that dies between taking and
202
+ # completing jobs would otherwise leave this request hanging forever. The
203
+ # bound is far above any legitimate CPU bulk encode.
204
+ if not job.done.wait(timeout=_JOB_WAIT_TIMEOUT_SECONDS):
205
+ raise RuntimeError(
206
+ f"Embedding micro-batch did not complete within "
207
+ f"{_JOB_WAIT_TIMEOUT_SECONDS:.0f}s"
208
+ )
209
+ if job.error is not None:
210
+ raise job.error
211
+ if job.result is None:
212
+ raise RuntimeError("Embedding micro-batch completed without a result")
213
+ return job.result
214
+
215
+
216
+ def _run_micro_batch_processor() -> None:
217
+ global _ACTIVE_BATCH_PROCESSORS
218
+ try:
219
+ while True:
220
+ jobs = _take_micro_batch()
221
+ if not jobs:
222
+ with _MICRO_BATCH_CONDITION:
223
+ if _MICRO_BATCH_QUEUE:
224
+ continue
225
+ _ACTIVE_BATCH_PROCESSORS -= 1
226
+ _MICRO_BATCH_CONDITION.notify_all()
227
+ return
228
+ _process_micro_batch(jobs)
229
+ except BaseException:
230
+ with _MICRO_BATCH_CONDITION:
231
+ _ACTIVE_BATCH_PROCESSORS -= 1
232
+ _MICRO_BATCH_CONDITION.notify_all()
233
+ raise
234
+
235
+
236
+ def _take_micro_batch() -> list[_EmbeddingJob]:
237
+ max_texts = _micro_batch_max_texts()
238
+ deadline = time.monotonic() + _micro_batch_delay_seconds()
239
+
240
+ with _MICRO_BATCH_CONDITION:
241
+ if not _MICRO_BATCH_QUEUE:
242
+ return []
243
+
244
+ first = _MICRO_BATCH_QUEUE.pop(0)
245
+ jobs = [first]
246
+ total_texts = len(first.texts)
247
+
248
+ while total_texts < max_texts:
249
+ compatible_index = next(
250
+ (
251
+ index
252
+ for index, candidate in enumerate(_MICRO_BATCH_QUEUE)
253
+ if candidate.model == first.model
254
+ and total_texts + len(candidate.texts) <= max_texts
255
+ ),
256
+ None,
257
+ )
258
+ if compatible_index is not None:
259
+ candidate = _MICRO_BATCH_QUEUE.pop(compatible_index)
260
+ jobs.append(candidate)
261
+ total_texts += len(candidate.texts)
262
+ continue
263
+
264
+ remaining = deadline - time.monotonic()
265
+ if remaining <= 0:
266
+ break
267
+ _MICRO_BATCH_CONDITION.wait(timeout=remaining)
268
+
269
+ return jobs
270
+
271
+
272
+ def _process_micro_batch(jobs: list[_EmbeddingJob]) -> None:
273
+ texts: list[str] = []
274
+ slices: list[tuple[_EmbeddingJob, int, int]] = []
275
+ for job in jobs:
276
+ start = len(texts)
277
+ texts.extend(job.texts)
278
+ slices.append((job, start, len(texts)))
279
+
280
+ try:
281
+ embeddings = _encode_texts_now(jobs[0].model, texts)
282
+ except BaseException as exc:
283
+ for job in jobs:
284
+ job.error = exc
285
+ job.done.set()
286
+ return
287
+
288
+ if len(embeddings) != len(texts):
289
+ # Slicing a short result would silently hand jobs truncated/empty
290
+ # vectors; fail every job loudly at the source instead.
291
+ mismatch = RuntimeError(
292
+ f"Embedding count mismatch: encoded {len(texts)} texts but got "
293
+ f"{len(embeddings)} embeddings"
294
+ )
295
+ for job in jobs:
296
+ job.error = mismatch
297
+ job.done.set()
298
+ return
299
+
300
+ for job, start, end in slices:
301
+ job.result = embeddings[start:end]
302
+ job.done.set()
303
+
304
+
305
+ def _encode_texts_now(model: str, texts: list[str]) -> list[list[float]]:
306
+ semaphore = _encode_semaphore()
307
+ # Non-blocking probe purely for observability: if no slot is free, this
308
+ # request will have to wait. The real acquire below blocks until a slot
309
+ # opens, so the request queues and is picked up later — never rejected.
310
+ if not semaphore.acquire(blocking=False):
311
+ logger.info(
312
+ "Embedding request queued; all %d encode slots busy",
313
+ _max_concurrency(),
314
+ )
315
+ semaphore.acquire()
316
+ try:
317
+ if is_nomic_model(model):
318
+ return NomicEmbedder.get().embed(texts)
319
+ if model == MINILM_MODEL:
320
+ return LocalEmbedder.get().embed(texts)
321
+ raise HTTPException(status_code=400, detail=f"Unsupported model: {model}")
322
+ finally:
323
+ semaphore.release()
324
+
325
+
326
+ def _activate_model(model: str) -> None:
327
+ if model not in _SUPPORTED_MODELS:
328
+ raise HTTPException(status_code=400, detail=f"Unsupported model: {model}")
329
+ global _ACTIVE_MODEL
330
+ with _ACTIVE_MODEL_LOCK:
331
+ if _ACTIVE_MODEL is None:
332
+ _ACTIVE_MODEL = model
333
+ return
334
+ if model != _ACTIVE_MODEL:
335
+ raise HTTPException(
336
+ status_code=409,
337
+ detail=(
338
+ "Embedding daemon already owns model "
339
+ f"{_ACTIVE_MODEL}; start a separate daemon for {model}"
340
+ ),
341
+ )
342
+
343
+
344
+ def _resize_embedding(vec: list[float], dimensions: int) -> list[float]:
345
+ if dimensions == len(vec):
346
+ return vec
347
+ if dimensions > len(vec):
348
+ raise HTTPException(
349
+ status_code=400,
350
+ detail=f"dimensions={dimensions} exceeds model output length {len(vec)}",
351
+ )
352
+ sliced = vec[:dimensions]
353
+ norm = math.sqrt(sum(value * value for value in sliced))
354
+ if norm <= 0:
355
+ return sliced
356
+ return [value / norm for value in sliced]
357
+
358
+
359
+ app = create_embedding_app(default_model=DEFAULT_OSS_EMBEDDING_MODEL)