claude-smart 0.2.41 → 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 (396) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/README.md +1 -1
  3. package/bin/claude-smart.js +86 -48
  4. package/package.json +10 -3
  5. package/plugin/.claude-plugin/plugin.json +9 -3
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +2 -2
  8. package/plugin/dashboard/next.config.ts +9 -1
  9. package/plugin/pyproject.toml +2 -2
  10. package/plugin/scripts/_lib.sh +91 -0
  11. package/plugin/scripts/backend-service.sh +46 -15
  12. package/plugin/scripts/cli.sh +29 -1
  13. package/plugin/scripts/codex-hook.js +72 -4
  14. package/plugin/scripts/dashboard-build.sh +1 -0
  15. package/plugin/scripts/dashboard-service.sh +1 -0
  16. package/plugin/scripts/ensure-plugin-root.sh +7 -14
  17. package/plugin/scripts/hook_entry.sh +1 -0
  18. package/plugin/scripts/smart-install.sh +18 -2
  19. package/plugin/src/claude_smart/cli.py +72 -38
  20. package/plugin/src/claude_smart/context_format.py +11 -12
  21. package/plugin/src/claude_smart/cs_cite.py +26 -12
  22. package/plugin/src/claude_smart/ids.py +13 -5
  23. package/plugin/uv.lock +1 -1
  24. package/plugin/vendor/reflexio/.env.example +53 -0
  25. package/plugin/vendor/reflexio/LICENSE +201 -0
  26. package/plugin/vendor/reflexio/README.md +338 -0
  27. package/plugin/vendor/reflexio/pyproject.toml +271 -0
  28. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  29. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  37. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  38. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  39. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  40. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +266 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +961 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  68. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  69. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  70. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  71. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  72. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  73. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  74. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  75. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  148. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  149. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  150. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  151. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  162. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  163. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  164. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  165. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  166. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1103 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +766 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  180. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  181. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  182. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  183. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +280 -0
  184. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  185. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  186. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  187. package/plugin/vendor/reflexio/reflexio/server/README.md +616 -0
  188. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  189. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  190. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api.py +2714 -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 +540 -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 +110 -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 +1595 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +112 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +469 -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 +210 -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 +255 -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 +177 -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 +699 -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_extraction_context/v4.0.2.prompt.md +254 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +279 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +127 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  276. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  277. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  278. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  279. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  281. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  282. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  283. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +340 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1626 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +351 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +468 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +777 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +91 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +689 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +960 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +741 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +734 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +800 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +70 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +671 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1253 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +372 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  380. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  381. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  382. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  383. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +568 -0
  384. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  385. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  386. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  387. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  388. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  389. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  390. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  391. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  392. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  393. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  394. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  395. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  396. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,116 @@
1
+ """
2
+ Feature flags module for gating features per organization.
3
+
4
+ Reads feature flag configuration from site_var and provides helpers
5
+ to check whether a given feature is enabled for an organization.
6
+ """
7
+
8
+ import logging
9
+
10
+ from reflexio.server.site_var.site_var_manager import SiteVarManager
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def _get_feature_flags_config() -> dict:
16
+ """
17
+ Load the feature_flags site var configuration.
18
+
19
+ Returns:
20
+ dict: The full feature flags config, or empty dict if not found.
21
+ """
22
+ config = SiteVarManager().get_site_var("feature_flags")
23
+ if config is None or not isinstance(config, dict):
24
+ logger.warning(
25
+ "feature_flags site var not found or invalid, defaulting to empty config"
26
+ )
27
+ return {}
28
+ return config
29
+
30
+
31
+ def is_feature_enabled(org_id: str, feature_name: str) -> bool:
32
+ """
33
+ Check if a feature is enabled for a given organization.
34
+
35
+ A feature is enabled if:
36
+ - The feature's "enabled" field is True (globally enabled), OR
37
+ - The org_id is in the feature's "enabled_org_ids" list.
38
+
39
+ If the feature is not found in config, it defaults to enabled (fail-open).
40
+
41
+ Args:
42
+ org_id (str): The organization ID to check
43
+ feature_name (str): The feature flag name (e.g. "deduplicator")
44
+
45
+ Returns:
46
+ bool: True if the feature is enabled for this org
47
+ """
48
+ config = _get_feature_flags_config()
49
+ feature_config = config.get(feature_name)
50
+
51
+ if feature_config is None:
52
+ # Unknown feature — default to enabled (fail-open)
53
+ return True
54
+
55
+ if feature_config.get("enabled", False):
56
+ return True
57
+
58
+ enabled_org_ids = feature_config.get("enabled_org_ids", [])
59
+ return org_id in enabled_org_ids
60
+
61
+
62
+ def get_all_feature_flags(org_id: str) -> dict[str, bool]:
63
+ """
64
+ Get the resolved enabled/disabled state of all feature flags for an organization.
65
+
66
+ Args:
67
+ org_id (str): The organization ID to check
68
+
69
+ Returns:
70
+ dict[str, bool]: Mapping of feature name to enabled status
71
+ """
72
+ config = _get_feature_flags_config()
73
+ result: dict[str, bool] = {}
74
+ for feature_name in config:
75
+ result[feature_name] = is_feature_enabled(org_id, feature_name)
76
+ return result
77
+
78
+
79
+ def is_invitation_only_enabled() -> bool:
80
+ """
81
+ Check if invitation-only registration mode is enabled globally.
82
+
83
+ Returns:
84
+ bool: True if invitation-only mode is enabled
85
+ """
86
+ config = _get_feature_flags_config()
87
+ invitation_config = config.get("invitation_only")
88
+ if invitation_config is None:
89
+ return False
90
+ return invitation_config.get("enabled", False)
91
+
92
+
93
+ def is_deduplicator_enabled(org_id: str) -> bool:
94
+ """
95
+ Convenience check for whether the deduplicator is enabled for an org.
96
+
97
+ Args:
98
+ org_id (str): The organization ID to check
99
+
100
+ Returns:
101
+ bool: True if deduplicator is enabled
102
+ """
103
+ return is_feature_enabled(org_id, "deduplicator")
104
+
105
+
106
+ def is_resumable_extraction_agent_enabled(org_id: str) -> bool:
107
+ """
108
+ Convenience check for whether classic extraction should use the resumable agent.
109
+
110
+ Args:
111
+ org_id (str): The organization ID to check
112
+
113
+ Returns:
114
+ bool: True if the resumable extraction agent is enabled
115
+ """
116
+ return is_feature_enabled(org_id, "resumable_extraction_agent")
@@ -0,0 +1,263 @@
1
+ import json
2
+ import logging
3
+ from pathlib import Path
4
+
5
+ import redis
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class SiteVarManager:
11
+ """
12
+ Manages site variables by loading JSON or text files from a source directory and caching them in Redis.
13
+ Each file in the source directory represents a site variable with the filename as the key.
14
+ Supports both .json and .txt files.
15
+ """
16
+
17
+ def __init__(self, source_dir: str | None = None, enable_redis: bool = False):
18
+ """
19
+ Initialize the SiteVarManager with a source directory for site variable files.
20
+
21
+ Args:
22
+ source_dir (Optional[str]): Directory containing JSON or text files for site variables
23
+ enable_redis (bool): Whether to enable Redis caching (default: False)
24
+ """
25
+ self.source_dir = source_dir or str(Path(__file__).parent / "site_var_sources")
26
+ self.enable_redis = enable_redis
27
+ self.redis = (
28
+ redis.Redis(host="localhost", port=6379, db=0) if enable_redis else None
29
+ )
30
+
31
+ # In-memory cache to avoid repeated file/Redis access
32
+ self._cache: dict[str, str | dict] = {}
33
+
34
+ # Ensure source directory exists
35
+ if not Path(self.source_dir).exists():
36
+ logger.warning(
37
+ "Source directory %s does not exist, creating it", self.source_dir
38
+ )
39
+ Path(self.source_dir).mkdir(parents=True, exist_ok=True)
40
+
41
+ def get_site_var(self, name: str) -> str | dict | None:
42
+ """
43
+ Get a site variable by name. Checks in-memory cache first, then Redis cache (if enabled), then loads from file.
44
+ Supports both JSON and text files.
45
+
46
+ Args:
47
+ name (str): Name of the site variable to retrieve
48
+
49
+ Returns:
50
+ Optional[str | dict]: The site variable value as JSON dict (for JSON files) or plain text (for text files), or None if not found
51
+ """
52
+ try:
53
+ # First check in-memory cache
54
+ if name in self._cache:
55
+ logger.debug("Retrieved site var %s from in-memory cache", name)
56
+ return self._cache[name]
57
+
58
+ # Then try to get from Redis cache if enabled
59
+ if self.enable_redis and self.redis is not None:
60
+ cached_value = self.redis.get(name)
61
+ if cached_value is not None:
62
+ logger.debug("Retrieved site var %s from Redis cache", name)
63
+ decoded_value = cached_value.decode("utf-8") # type: ignore[reportAttributeAccessIssue]
64
+ # Try to parse as JSON for dict values
65
+ try:
66
+ parsed_value = json.loads(decoded_value)
67
+ self._cache[name] = parsed_value
68
+ return parsed_value
69
+ except json.JSONDecodeError:
70
+ # It's a plain text value
71
+ self._cache[name] = decoded_value
72
+ return decoded_value
73
+
74
+ # If not in cache or Redis disabled, try to load from file
75
+ content = self._load_from_file(name)
76
+ if content is not None:
77
+ # Cache in memory
78
+ self._cache[name] = content
79
+
80
+ # Cache in Redis for future use if enabled
81
+ if self.enable_redis and self.redis is not None:
82
+ # Convert dict to JSON string for Redis storage
83
+ redis_value = (
84
+ json.dumps(content) if isinstance(content, dict) else content
85
+ )
86
+ self.redis.set(name, redis_value)
87
+ logger.debug("Cached site var %s in Redis", name)
88
+ return content
89
+ logger.warning("Site var %s not found in Redis or files", name)
90
+ return None
91
+
92
+ except redis.RedisError as e:
93
+ logger.error("Redis error while getting site var %s: %s", name, str(e))
94
+ # Fallback to file-based loading
95
+ content = self._load_from_file(name)
96
+ if content is not None:
97
+ self._cache[name] = content
98
+ return content
99
+ except Exception as e:
100
+ logger.error("Error loading site var %s: %s", name, str(e))
101
+ return None
102
+
103
+ def evict_cache(self) -> None:
104
+ """
105
+ Evict (clear) all cached site variables from in-memory cache.
106
+ This forces fresh loading from Redis or files on next access.
107
+ """
108
+ cache_size = len(self._cache)
109
+ self._cache.clear()
110
+ logger.info("Evicted %d site variables from in-memory cache", cache_size)
111
+
112
+ def get_cache_stats(self) -> dict[str, int]:
113
+ """
114
+ Get statistics about the in-memory cache.
115
+
116
+ Returns:
117
+ dict[str, int]: Cache statistics including size and key count
118
+ """
119
+ return {
120
+ "cache_size": len(self._cache),
121
+ "cached_keys": len(list(self._cache.keys())),
122
+ }
123
+
124
+ def load_all_site_vars(self) -> dict[str, str | dict]:
125
+ """
126
+ Load all site variables from files in the source directory and cache them in memory and Redis (if enabled).
127
+ Supports both JSON and text files.
128
+
129
+ Returns:
130
+ dict[str, str | dict]: Dictionary mapping site var names to their values
131
+ """
132
+ site_vars = {}
133
+
134
+ try:
135
+ if not Path(self.source_dir).exists():
136
+ logger.warning("Source directory %s does not exist", self.source_dir)
137
+ return site_vars
138
+
139
+ for filename in [p.name for p in Path(self.source_dir).iterdir()]:
140
+ if filename.endswith((".json", ".txt")):
141
+ name = self._get_name_from_filename(filename)
142
+ value = self.get_site_var(name) # This will use cache automatically
143
+ if value is not None:
144
+ site_vars[name] = value
145
+
146
+ logger.info(
147
+ "Loaded %d site variables, %d now in cache",
148
+ len(site_vars),
149
+ len(self._cache),
150
+ )
151
+ return site_vars
152
+
153
+ except Exception as e:
154
+ logger.error("Error loading site variables from directory: %s", str(e))
155
+ return site_vars
156
+
157
+ def list_site_vars(self) -> list[str]:
158
+ """
159
+ List all available site variable names from the source directory.
160
+ Supports both .json and .txt files.
161
+
162
+ Returns:
163
+ list[str]: List of site variable names
164
+ """
165
+ try:
166
+ if not Path(self.source_dir).exists():
167
+ return []
168
+
169
+ return [
170
+ entry.stem
171
+ for entry in Path(self.source_dir).iterdir()
172
+ if entry.name.endswith((".json", ".txt"))
173
+ ]
174
+
175
+ except Exception as e:
176
+ logger.error("Error listing site variables: %s", str(e))
177
+ return []
178
+
179
+ def _find_file_path(self, name: str) -> str | None:
180
+ """
181
+ Find the file path for a site variable, checking both .json and .txt extensions.
182
+
183
+ Args:
184
+ name (str): Name of the site variable
185
+
186
+ Returns:
187
+ Optional[str]: Path to the file if found, None otherwise
188
+ """
189
+ json_path = Path(self.source_dir) / f"{name}.json"
190
+ txt_path = Path(self.source_dir) / f"{name}.txt"
191
+
192
+ if json_path.exists():
193
+ return str(json_path)
194
+ if txt_path.exists():
195
+ return str(txt_path)
196
+ return None
197
+
198
+ def _load_file_content(self, file_path: str) -> str | dict | None:
199
+ """
200
+ Load content from a file, handling both JSON and text files.
201
+
202
+ Args:
203
+ file_path (str): Path to the file to load
204
+
205
+ Returns:
206
+ Optional[str]: File content as string, or None if error
207
+ """
208
+ try:
209
+ if not Path(file_path).exists():
210
+ logger.error("File %s does not exist", file_path)
211
+ return None
212
+
213
+ if file_path.endswith(".txt"):
214
+ with Path(file_path).open(encoding="utf-8") as f:
215
+ return f.read().strip()
216
+ if file_path.endswith(".json"):
217
+ try:
218
+ # Parse to validate JSON, then return as string
219
+ with Path(file_path).open(encoding="utf-8") as f:
220
+ return json.load(f)
221
+ except json.JSONDecodeError as e:
222
+ logger.error("Invalid JSON in file %s: %s", file_path, str(e))
223
+ return None
224
+ else:
225
+ logger.error(
226
+ "Unsupported file type: %s. Use 'json' or 'txt'", file_path
227
+ )
228
+ return None
229
+
230
+ except OSError as e:
231
+ logger.error("Error reading file %s: %s", file_path, str(e))
232
+ return None
233
+
234
+ def _load_from_file(self, name: str) -> str | dict | None:
235
+ """
236
+ Load a site variable directly from file (fallback method).
237
+
238
+ Args:
239
+ name (str): Name of the site variable
240
+
241
+ Returns:
242
+ Optional[str]: The site variable value, or None if not found
243
+ """
244
+ file_path = self._find_file_path(name)
245
+ if file_path:
246
+ return self._load_file_content(file_path)
247
+ return None
248
+
249
+ def _get_name_from_filename(self, filename: str) -> str:
250
+ """
251
+ Extract the site variable name from a filename by removing the extension.
252
+
253
+ Args:
254
+ filename (str): Filename with extension
255
+
256
+ Returns:
257
+ str: Site variable name without extension
258
+ """
259
+ if filename.endswith(".json"):
260
+ return filename[:-5]
261
+ if filename.endswith(".txt"):
262
+ return filename[:-4]
263
+ return filename
@@ -0,0 +1,13 @@
1
+ {
2
+ "invitation_only": {
3
+ "enabled": true
4
+ },
5
+ "deduplicator": {
6
+ "enabled": true,
7
+ "enabled_org_ids": []
8
+ },
9
+ "resumable_extraction_agent": {
10
+ "enabled": true,
11
+ "enabled_org_ids": []
12
+ }
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "should_run_model_name": "",
3
+ "default_generation_model_name": "",
4
+ "default_evaluate_model_name": "",
5
+ "embedding_model_name": "",
6
+ "pre_retrieval_model_name": ""
7
+ }
@@ -0,0 +1,158 @@
1
+ """Optional tracing hook for request-path profiling.
2
+
3
+ This module intentionally has no observability-vendor dependency. Deployments
4
+ that want tracing can register a tracer; deployments that do not register one
5
+ pay only a cheap context-manager/no-op cost.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from collections.abc import Iterator, Mapping
12
+ from contextlib import AbstractContextManager, contextmanager
13
+ from typing import Any, Protocol
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class TraceSpan(Protocol):
19
+ """Minimal span handle exposed to shared Reflexio code."""
20
+
21
+ def set_data(self, key: str, value: Any) -> None:
22
+ """Attach low-cardinality metadata to the active span."""
23
+ ...
24
+
25
+
26
+ class Tracer(Protocol):
27
+ """Process-global tracer interface configured by enterprise startup."""
28
+
29
+ def span(self, name: str, **data: Any) -> AbstractContextManager[TraceSpan]:
30
+ """Create a span context manager."""
31
+ ...
32
+
33
+
34
+ class _NoopTraceSpan:
35
+ def set_data(self, key: str, value: Any) -> None:
36
+ del key, value
37
+
38
+
39
+ _NOOP_SPAN = _NoopTraceSpan()
40
+ _tracer: Tracer | None = None
41
+
42
+
43
+ def configure_tracer(tracer: Tracer | None) -> None:
44
+ """Set the process-global tracer.
45
+
46
+ Args:
47
+ tracer: Tracer implementation, or None to disable tracing.
48
+ """
49
+ global _tracer
50
+ _tracer = tracer
51
+
52
+
53
+ @contextmanager
54
+ def profile_step(name: str, **data: Any) -> Iterator[TraceSpan]:
55
+ """Profile a named step if tracing is configured.
56
+
57
+ Tracing must never make product requests fail. Errors from creating,
58
+ entering, or exiting the tracing span are logged and swallowed. Exceptions
59
+ raised by the profiled product code are still propagated unchanged.
60
+ """
61
+ tracer = _tracer
62
+ if tracer is None:
63
+ yield _NOOP_SPAN
64
+ return
65
+
66
+ try:
67
+ span_cm = tracer.span(name, **data)
68
+ span = span_cm.__enter__()
69
+ except Exception as exc: # noqa: BLE001
70
+ logger.warning("Tracer failed to start span %s: %s", name, exc)
71
+ yield _NOOP_SPAN
72
+ return
73
+
74
+ try:
75
+ yield span
76
+ except BaseException as exc:
77
+ try:
78
+ span_cm.__exit__(type(exc), exc, exc.__traceback__)
79
+ except Exception as tracer_exc: # noqa: BLE001
80
+ logger.warning("Tracer failed to finish span %s: %s", name, tracer_exc)
81
+ raise
82
+ else:
83
+ try:
84
+ span_cm.__exit__(None, None, None)
85
+ except Exception as exc: # noqa: BLE001
86
+ logger.warning("Tracer failed to finish span %s: %s", name, exc)
87
+
88
+
89
+ def set_span_data(span: TraceSpan, values: Mapping[str, Any]) -> None:
90
+ """Best-effort helper for attaching multiple span fields."""
91
+ for key, value in values.items():
92
+ try:
93
+ span.set_data(key, value)
94
+ except Exception as exc: # noqa: BLE001
95
+ logger.warning("Tracer failed to set span data %s: %s", key, exc)
96
+
97
+
98
+ @contextmanager
99
+ def sentry_tags(**tags: Any) -> Iterator[None]:
100
+ """Attach tags to any Sentry events produced inside the block.
101
+
102
+ Used inside ``except`` handlers, immediately wrapping a
103
+ ``logger.exception(...)`` call, so the event auto-captured by
104
+ Sentry's ``LoggingIntegration`` is filterable by org / subsystem.
105
+
106
+ No-op when ``sentry-sdk`` is not installed (the OS package does not
107
+ declare it as a dependency; enterprise deployments pull it in).
108
+ Tag values that are ``None`` are skipped to avoid noisy "None" tags.
109
+
110
+ Args:
111
+ **tags: arbitrary tag name → value pairs. Values are stringified.
112
+
113
+ Yields:
114
+ None. Re-enters the active Sentry scope for the duration of the
115
+ ``with`` block.
116
+ """
117
+ try:
118
+ import sentry_sdk # type: ignore[import-not-found]
119
+ except ImportError:
120
+ yield
121
+ return
122
+
123
+ # Mirrors `profile_step` above: instrumentation must never make a product
124
+ # request fail. If the Sentry SDK throws while opening or closing the
125
+ # scope, log and continue rather than letting the exception escape the
126
+ # caller's `with sentry_tags(...)` block and mask the original failure.
127
+ # `new_scope()` is the sentry-sdk >=2.0 replacement for the deprecated
128
+ # `push_scope()`; the AttributeError on the older 1.x SDK is caught by
129
+ # the broad `except` below so the helper still degrades cleanly.
130
+ try:
131
+ scope_cm = sentry_sdk.new_scope()
132
+ scope = scope_cm.__enter__()
133
+ except Exception as exc: # noqa: BLE001
134
+ logger.warning("Failed to open Sentry scope for tags: %s", exc)
135
+ yield
136
+ return
137
+
138
+ for key, value in tags.items():
139
+ if value is None:
140
+ continue
141
+ try:
142
+ scope.set_tag(key, str(value))
143
+ except Exception as exc: # noqa: BLE001
144
+ logger.warning("Failed to set Sentry tag %s: %s", key, exc)
145
+
146
+ try:
147
+ yield
148
+ except BaseException as exc:
149
+ try:
150
+ scope_cm.__exit__(type(exc), exc, exc.__traceback__)
151
+ except Exception as cleanup_exc: # noqa: BLE001
152
+ logger.warning("Failed to close Sentry scope: %s", cleanup_exc)
153
+ raise
154
+ else:
155
+ try:
156
+ scope_cm.__exit__(None, None, None)
157
+ except Exception as exc: # noqa: BLE001
158
+ logger.warning("Failed to close Sentry scope: %s", exc)
@@ -0,0 +1,113 @@
1
+ """Optional usage metrics hook.
2
+
3
+ This module intentionally has no storage or vendor dependency. Deployments that
4
+ want usage metrics can register a recorder; deployments that do not register one
5
+ pay only a cheap function-call/no-op cost.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import time
12
+ from collections.abc import Callable, Mapping
13
+ from dataclasses import dataclass, field
14
+ from typing import Any
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @dataclass(slots=True, frozen=True)
20
+ class UsageEvent:
21
+ org_id: str
22
+ event_name: str
23
+ event_category: str
24
+ user_id: str | None = None
25
+ request_id: str | None = None
26
+ session_id: str | None = None
27
+ pipeline: str | None = None
28
+ entity_type: str | None = None
29
+ entity_id: str | None = None
30
+ extractor_name: str | None = None
31
+ playbook_name: str | None = None
32
+ source: str | None = None
33
+ agent_version: str | None = None
34
+ backend: str | None = None
35
+ outcome: str | None = None
36
+ count_value: int = 1
37
+ duration_ms: int | None = None
38
+ error_kind: str | None = None
39
+ metadata: Mapping[str, Any] = field(default_factory=dict)
40
+ created_at: float = field(default_factory=time.time)
41
+
42
+
43
+ UsageEventRecorder = Callable[[UsageEvent], None]
44
+
45
+ _recorder: UsageEventRecorder | None = None
46
+
47
+
48
+ def configure_usage_event_recorder(recorder: UsageEventRecorder | None) -> None:
49
+ """Set the process-global usage metrics recorder.
50
+
51
+ Args:
52
+ recorder: Callable that accepts UsageEvent, or None to disable metrics.
53
+ """
54
+ global _recorder
55
+ _recorder = recorder
56
+
57
+
58
+ def record_usage_event(
59
+ *,
60
+ org_id: str,
61
+ event_name: str,
62
+ event_category: str,
63
+ user_id: str | None = None,
64
+ request_id: str | None = None,
65
+ session_id: str | None = None,
66
+ pipeline: str | None = None,
67
+ entity_type: str | None = None,
68
+ entity_id: str | None = None,
69
+ extractor_name: str | None = None,
70
+ playbook_name: str | None = None,
71
+ source: str | None = None,
72
+ agent_version: str | None = None,
73
+ backend: str | None = None,
74
+ outcome: str | None = None,
75
+ count_value: int = 1,
76
+ duration_ms: int | None = None,
77
+ error_kind: str | None = None,
78
+ metadata: Mapping[str, Any] | None = None,
79
+ ) -> None:
80
+ """Record one usage event if a recorder is configured.
81
+
82
+ The product path must never fail because metrics failed, so this function
83
+ catches and logs all recorder errors.
84
+ """
85
+ recorder = _recorder
86
+ if recorder is None:
87
+ return
88
+ try:
89
+ recorder(
90
+ UsageEvent(
91
+ org_id=str(org_id),
92
+ event_name=event_name,
93
+ event_category=event_category,
94
+ user_id=user_id,
95
+ request_id=request_id,
96
+ session_id=session_id,
97
+ pipeline=pipeline,
98
+ entity_type=entity_type,
99
+ entity_id=entity_id,
100
+ extractor_name=extractor_name,
101
+ playbook_name=playbook_name,
102
+ source=source,
103
+ agent_version=agent_version,
104
+ backend=backend,
105
+ outcome=outcome,
106
+ count_value=count_value,
107
+ duration_ms=duration_ms,
108
+ error_kind=error_kind,
109
+ metadata=metadata or {},
110
+ )
111
+ )
112
+ except Exception as exc: # noqa: BLE001
113
+ logger.warning("Usage metrics recorder failed: %s", exc)