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,156 @@
1
+ """Singleton scheduler for delayed session evaluation.
2
+
3
+ Uses a single daemon thread with a min-heap priority queue.
4
+ Each new request upserts the fire time for its group.
5
+ When the fire time arrives, a daemon thread runs the evaluation callback.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import heapq
11
+ import logging
12
+ import os
13
+ import threading
14
+ import time
15
+ from collections.abc import Callable
16
+
17
+ from reflexio.server.services.agent_success_evaluation import _eval_health
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # Delay in seconds before evaluating a group after the last request
22
+ GROUP_EVALUATION_DELAY_SECONDS = 600 # 10 minutes
23
+
24
+ IS_TEST_ENV = os.environ.get("IS_TEST_ENV", "false").strip() == "true"
25
+ _EFFECTIVE_DELAY_SECONDS = 30 if IS_TEST_ENV else GROUP_EVALUATION_DELAY_SECONDS
26
+
27
+ # Type alias for the scheduling key
28
+ GroupKey = tuple[str, str, str] # (org_id, user_id, session_id)
29
+
30
+
31
+ class GroupEvaluationScheduler:
32
+ """Singleton scheduler that fires group evaluations after a period of inactivity.
33
+
34
+ Uses one daemon thread with a min-heap. Each new request upserts the fire time
35
+ for its group. Handles hundreds of concurrent groups efficiently.
36
+ """
37
+
38
+ _instance = None
39
+ _lock = threading.Lock()
40
+
41
+ @classmethod
42
+ def get_instance(cls) -> GroupEvaluationScheduler:
43
+ """Get or create the singleton scheduler instance.
44
+
45
+ Returns:
46
+ GroupEvaluationScheduler: The singleton instance
47
+ """
48
+ if cls._instance is None:
49
+ with cls._lock:
50
+ if cls._instance is None:
51
+ cls._instance = cls()
52
+ return cls._instance
53
+
54
+ def __init__(self) -> None:
55
+ self._scheduled: dict[GroupKey, tuple[float, Callable]] = {}
56
+ self._heap: list[tuple[float, GroupKey]] = []
57
+ self._mutex = threading.Lock()
58
+ self._wake_event = threading.Event()
59
+ self._thread = threading.Thread(
60
+ target=self._scheduler_loop, daemon=True, name="group-eval-scheduler"
61
+ )
62
+ self._thread.start()
63
+ logger.info("GroupEvaluationScheduler started")
64
+
65
+ def schedule(self, key: GroupKey, callback: Callable) -> None:
66
+ """Schedule or reschedule a group evaluation.
67
+
68
+ If the group already has a pending evaluation, its fire time is updated
69
+ (slid forward). The callback will be invoked after GROUP_EVALUATION_DELAY_SECONDS
70
+ of inactivity.
71
+
72
+ Args:
73
+ key: Tuple of (org_id, user_id, session_id)
74
+ callback: Zero-argument callable to run when the timer fires
75
+ """
76
+ fire_time = time.monotonic() + _EFFECTIVE_DELAY_SECONDS
77
+ with self._mutex:
78
+ self._scheduled[key] = (fire_time, callback)
79
+ heapq.heappush(self._heap, (fire_time, key))
80
+ self._wake_event.set()
81
+ logger.info(
82
+ "Scheduled group evaluation for key=%s fire_time=%.1f", key, fire_time
83
+ )
84
+
85
+ def _scheduler_loop(self) -> None:
86
+ """Main loop for the scheduler thread.
87
+
88
+ Pops due items from the heap, verifies they are still current
89
+ (not superseded by a newer schedule), and spawns daemon threads
90
+ to run the callback.
91
+ """
92
+ while True:
93
+ try:
94
+ _eval_health.record_tick()
95
+ with self._mutex:
96
+ next_fire_time = self._heap[0][0] if self._heap else None
97
+
98
+ if next_fire_time is None:
99
+ # Nothing scheduled, wait for a wake signal
100
+ self._wake_event.wait()
101
+ self._wake_event.clear()
102
+ continue
103
+
104
+ now = time.monotonic()
105
+ wait_seconds = next_fire_time - now
106
+
107
+ if wait_seconds > 0:
108
+ # Wait until the next fire time or a wake signal
109
+ self._wake_event.wait(timeout=wait_seconds)
110
+ self._wake_event.clear()
111
+ continue
112
+
113
+ # Process due items
114
+ with self._mutex:
115
+ while self._heap and self._heap[0][0] <= time.monotonic():
116
+ fire_time, key = heapq.heappop(self._heap)
117
+
118
+ # Check if this entry is still current (not superseded)
119
+ current = self._scheduled.get(key)
120
+ if current is None:
121
+ continue
122
+ current_fire_time, callback = current
123
+ if abs(current_fire_time - fire_time) > 0.001:
124
+ # This entry was superseded by a newer schedule
125
+ continue
126
+
127
+ # Remove from scheduled map and fire
128
+ del self._scheduled[key]
129
+
130
+ # Spawn daemon thread for the callback
131
+ t = threading.Thread(
132
+ target=self._run_callback,
133
+ args=(key, callback),
134
+ daemon=True,
135
+ name=f"group-eval-{key[2][:20]}",
136
+ )
137
+ t.start()
138
+
139
+ except Exception:
140
+ logger.exception("Error in group evaluation scheduler loop")
141
+ # Brief sleep to avoid tight error loops
142
+ time.sleep(1)
143
+
144
+ @staticmethod
145
+ def _run_callback(key: GroupKey, callback: Callable) -> None:
146
+ """Run the evaluation callback, catching any exceptions.
147
+
148
+ Args:
149
+ key: The group key for logging
150
+ callback: The evaluation callback to run
151
+ """
152
+ try:
153
+ logger.info("Firing group evaluation for key=%s", key)
154
+ callback()
155
+ except Exception:
156
+ logger.exception("Group evaluation callback failed for key=%s", key)
@@ -0,0 +1,340 @@
1
+ """Runner for group-level agent success evaluation.
2
+
3
+ Fetches all requests and interactions for a session,
4
+ checks completion status, runs evaluation, and marks the group as evaluated.
5
+ """
6
+
7
+ import logging
8
+ import random
9
+ from collections import defaultdict
10
+ from datetime import UTC, datetime
11
+
12
+ from reflexio.models.api_schema.domain.entities import Interaction
13
+ from reflexio.models.api_schema.internal_schema import RequestInteractionDataModel
14
+ from reflexio.server.api_endpoints.request_context import RequestContext
15
+ from reflexio.server.llm.litellm_client import LiteLLMClient
16
+ from reflexio.server.services.agent_success_evaluation import _eval_health
17
+ from reflexio.server.services.agent_success_evaluation._eval_health import SkipReason
18
+ from reflexio.server.services.agent_success_evaluation.agent_success_evaluation_service import (
19
+ AgentSuccessEvaluationService,
20
+ )
21
+ from reflexio.server.services.agent_success_evaluation.agent_success_evaluation_utils import (
22
+ AgentSuccessEvaluationRequest,
23
+ )
24
+ from reflexio.server.services.agent_success_evaluation.delayed_group_evaluator import (
25
+ _EFFECTIVE_DELAY_SECONDS,
26
+ )
27
+ from reflexio.server.services.shadow_comparison.judge import ShadowComparisonJudge
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ # Key prefix for operation state tracking
32
+ OPERATION_STATE_KEY_PREFIX = "agent_success_group_eval"
33
+
34
+
35
+ def _build_state_key(org_id: str, user_id: str, session_id: str) -> str:
36
+ """Build the operation state key for a session.
37
+
38
+ Args:
39
+ org_id: Organization ID
40
+ user_id: User ID
41
+ session_id: Session identifier
42
+
43
+ Returns:
44
+ str: The operation state key
45
+ """
46
+ return f"{OPERATION_STATE_KEY_PREFIX}::{org_id}::{user_id}::{session_id}"
47
+
48
+
49
+ def run_group_evaluation(
50
+ org_id: str,
51
+ user_id: str,
52
+ session_id: str,
53
+ agent_version: str,
54
+ source: str | None,
55
+ request_context: RequestContext,
56
+ llm_client: LiteLLMClient,
57
+ *,
58
+ force_regenerate: bool = False,
59
+ ) -> None:
60
+ """Run agent success evaluation for an entire session.
61
+
62
+ Steps:
63
+ 1. Check if already evaluated via operation state (skipped when force_regenerate)
64
+ 2. Fetch all requests for the session
65
+ 3. Verify completion (latest request created_at >= delay ago; skipped when force_regenerate)
66
+ 4. Fetch interactions and build data models
67
+ 5. Capture prior result_ids (when regenerating) so they
68
+ can be removed AFTER the new save lands
69
+ 6. Run evaluation service (which saves new rows)
70
+ 7. On success, delete the captured prior rows by id — the new rows have
71
+ fresh auto-increment ids that do not overlap. A failure here leaves
72
+ the session in a consistent pre-regen state instead of zero rows.
73
+ 8. Mark as evaluated in operation state
74
+
75
+ Args:
76
+ org_id: Organization ID
77
+ user_id: User ID who owns the requests
78
+ session_id: Session identifier
79
+ agent_version: Agent version string
80
+ source: Source of the interactions
81
+ request_context: Request context with storage and configurator
82
+ llm_client: LLM client for evaluation
83
+ force_regenerate: When True, bypass the already-evaluated short-circuit
84
+ and the completeness delay gate so the regenerate worker can
85
+ re-evaluate sessions of any age regardless of prior state.
86
+ """
87
+ storage = request_context.storage
88
+ state_key = _build_state_key(org_id, user_id, session_id)
89
+
90
+ # 1. Check if already evaluated — skipped in force_regenerate mode so the
91
+ # regenerate worker can re-evaluate a session that's already been marked.
92
+ if not force_regenerate:
93
+ existing_state = storage.get_operation_state(state_key) # type: ignore[reportOptionalMemberAccess]
94
+ if existing_state and isinstance(existing_state.get("operation_state"), dict):
95
+ op_state = existing_state["operation_state"]
96
+ if op_state.get("evaluated"):
97
+ _eval_health.record_skip(SkipReason.ALREADY_EVALUATED)
98
+ logger.info("Session %s already evaluated, skipping", session_id)
99
+ return
100
+
101
+ # 2. Fetch all requests for the session
102
+ requests = storage.get_requests_by_session(user_id, session_id) # type: ignore[reportOptionalMemberAccess]
103
+ if not requests:
104
+ _eval_health.record_skip(SkipReason.NO_REQUESTS)
105
+ logger.info("No requests found for session %s, skipping", session_id)
106
+ return
107
+
108
+ # 3. Verify completion: latest request must be >= delay ago — skipped in
109
+ # force_regenerate mode so the operator can re-evaluate any session.
110
+ if not force_regenerate:
111
+ latest_created_at = max(r.created_at for r in requests)
112
+ now = int(datetime.now(UTC).timestamp())
113
+ elapsed = now - latest_created_at
114
+ if elapsed < _EFFECTIVE_DELAY_SECONDS:
115
+ _eval_health.record_skip(SkipReason.NOT_YET_COMPLETE)
116
+ logger.info(
117
+ "Session %s not yet complete (latest request %ds ago, need %ds), skipping",
118
+ session_id,
119
+ elapsed,
120
+ _EFFECTIVE_DELAY_SECONDS,
121
+ )
122
+ return
123
+
124
+ # 4. Fetch interactions for all requests
125
+ request_ids = [r.request_id for r in requests]
126
+ all_interactions = storage.get_interactions_by_request_ids(request_ids) # type: ignore[reportOptionalMemberAccess]
127
+ if not all_interactions:
128
+ _eval_health.record_skip(SkipReason.NO_INTERACTIONS)
129
+ logger.info("No interactions found for session %s, skipping", session_id)
130
+ return
131
+
132
+ # Group interactions by request_id
133
+ interactions_by_request: dict[str, list] = defaultdict(list)
134
+ for interaction in all_interactions:
135
+ interactions_by_request[interaction.request_id].append(interaction)
136
+
137
+ # Build RequestInteractionDataModel list, sorted by request created_at
138
+ requests_sorted = sorted(requests, key=lambda r: r.created_at)
139
+ request_interaction_data_models = []
140
+ for req in requests_sorted:
141
+ req_interactions = interactions_by_request.get(req.request_id, [])
142
+ if req_interactions:
143
+ # Sort interactions by created_at within each request
144
+ req_interactions.sort(key=lambda i: i.created_at)
145
+ request_interaction_data_models.append(
146
+ RequestInteractionDataModel(
147
+ session_id=session_id,
148
+ request=req,
149
+ interactions=req_interactions,
150
+ )
151
+ )
152
+
153
+ if not request_interaction_data_models:
154
+ _eval_health.record_skip(SkipReason.NO_DATA_MODELS)
155
+ logger.info(
156
+ "No request interaction data models built for session %s, skipping",
157
+ session_id,
158
+ )
159
+ return
160
+
161
+ # 5. When regenerating, capture the prior result_ids
162
+ # so we can delete ONLY them AFTER the new rows have been saved. Doing
163
+ # the delete before the LLM call risks wiping the session's rows if the
164
+ # call fails (rate limit, network) and nothing replaces them. The new
165
+ # rows always get fresh auto-increment ids, so deleting the captured set
166
+ # afterwards cannot remove the new rows.
167
+ old_result_ids: list[int] = []
168
+ if force_regenerate:
169
+ # Eval rows per session are tiny (usually 1), so pulling a
170
+ # generous limit and filtering in-process is cheap and avoids adding
171
+ # a third query shape to the storage contract.
172
+ prior_rows = storage.get_agent_success_evaluation_results( # type: ignore[reportOptionalMemberAccess]
173
+ limit=10000, agent_version=agent_version
174
+ )
175
+ old_result_ids = [
176
+ r.result_id
177
+ for r in prior_rows
178
+ if r.session_id == session_id
179
+ ]
180
+
181
+ logger.info(
182
+ "Running group evaluation for session=%s with %d requests and %d interactions"
183
+ " (force_regenerate=%s, prior_result_ids=%d)",
184
+ session_id,
185
+ len(request_interaction_data_models),
186
+ len(all_interactions),
187
+ force_regenerate,
188
+ len(old_result_ids),
189
+ )
190
+
191
+ evaluation_request = AgentSuccessEvaluationRequest(
192
+ session_id=session_id,
193
+ agent_version=agent_version,
194
+ source=source,
195
+ request_interaction_data_models=request_interaction_data_models,
196
+ )
197
+
198
+ evaluation_service = AgentSuccessEvaluationService(
199
+ llm_client=llm_client, request_context=request_context
200
+ )
201
+ evaluation_service.run(evaluation_request)
202
+
203
+ if evaluation_service.has_run_failures():
204
+ logger.warning(
205
+ "Group evaluation for session=%s had failures (save_failed=%s);"
206
+ " preserving %d prior result row(s) and skipping evaluated marker",
207
+ session_id,
208
+ evaluation_service.last_run_save_failed,
209
+ len(old_result_ids),
210
+ )
211
+ return
212
+
213
+ if evaluation_service.last_run_saved_result_count == 0:
214
+ logger.warning(
215
+ "Group evaluation for session=%s saved no results;"
216
+ " preserving %d prior result row(s) and skipping evaluated marker",
217
+ session_id,
218
+ len(old_result_ids),
219
+ )
220
+ return
221
+
222
+ # F1: per-turn shadow comparison. Dispatched only AFTER the regular
223
+ # success eval succeeds — a session whose success grade is unreliable
224
+ # would yield noisy verdicts that mislead the headline metric. The
225
+ # dispatch loop swallows per-interaction failures so one judge call
226
+ # cannot abort an entire batch.
227
+ _dispatch_shadow_comparison_judge(
228
+ storage=storage,
229
+ interactions=all_interactions,
230
+ session_id=session_id,
231
+ agent_version=agent_version,
232
+ request_context=request_context,
233
+ llm_client=llm_client,
234
+ )
235
+
236
+ # 6. New rows saved successfully — now safe to remove the captured prior
237
+ # rows. New rows have fresh auto-increment result_ids that do not overlap
238
+ # with old_result_ids, so this cannot delete the regenerated verdict.
239
+ if old_result_ids:
240
+ deleted = storage.delete_agent_success_evaluation_results_by_ids( # type: ignore[reportOptionalMemberAccess]
241
+ old_result_ids
242
+ )
243
+ logger.info(
244
+ "Regenerate cleanup: deleted %d prior result row(s) for session=%s"
245
+ " (expected %d)",
246
+ deleted,
247
+ session_id,
248
+ len(old_result_ids),
249
+ )
250
+
251
+ # 7. Mark as evaluated
252
+ evaluated_at = int(datetime.now(UTC).timestamp())
253
+ storage.upsert_operation_state( # type: ignore[reportOptionalMemberAccess]
254
+ state_key,
255
+ {"evaluated": True, "evaluated_at": evaluated_at},
256
+ )
257
+ logger.info("Marked session %s as evaluated at %d", session_id, evaluated_at)
258
+
259
+
260
+ def _dispatch_shadow_comparison_judge(
261
+ *,
262
+ storage, # noqa: ANN001 — BaseStorage; imported lazily to avoid cycles
263
+ interactions: list[Interaction],
264
+ session_id: str,
265
+ agent_version: str,
266
+ request_context: RequestContext,
267
+ llm_client: LiteLLMClient,
268
+ ) -> None:
269
+ """F1: grade each shadow-bearing interaction with the per-turn judge.
270
+
271
+ Iterates the session's interactions, skips any without ``shadow_content``,
272
+ invokes :class:`ShadowComparisonJudge.judge_turn`, and persists each
273
+ returned verdict via ``storage.save_shadow_comparison_verdict``. Per-
274
+ interaction exceptions are logged and the loop continues — partial
275
+ verdict sets are strictly better than nothing for the headline metric.
276
+
277
+ Args:
278
+ storage: The session storage. Must implement
279
+ ``save_shadow_comparison_verdict`` (currently SQLite + Supabase
280
+ + disk; backends without it surface ``NotImplementedError`` at
281
+ save time and the loop logs+continues).
282
+ interactions (list[Interaction]): Every interaction in the session,
283
+ in chronological order. Only those with non-empty
284
+ ``shadow_content`` are graded.
285
+ session_id (str): Denormalized onto each verdict.
286
+ agent_version (str): Denormalized onto each verdict.
287
+ request_context (RequestContext): Provides the configurator (for
288
+ the pinned ``shadow_comparison_judge_prompt_version``) and the
289
+ shared ``prompt_manager``.
290
+ llm_client (LiteLLMClient): The unified LLM client the judge uses
291
+ for the structured-output call.
292
+
293
+ Returns:
294
+ None: Verdicts are persisted as a side effect; the caller does not
295
+ need the count for control flow.
296
+ """
297
+ config = request_context.configurator.get_config() # type: ignore[reportOptionalMemberAccess]
298
+ judge = ShadowComparisonJudge(
299
+ llm_client=llm_client,
300
+ prompt_manager=request_context.prompt_manager, # type: ignore[reportOptionalMemberAccess]
301
+ prompt_version=config.shadow_comparison_judge_prompt_version,
302
+ )
303
+ rng = random.Random() # noqa: S311 — position randomization, not crypto
304
+ saved_count = 0
305
+
306
+ for interaction in interactions:
307
+ if not interaction.shadow_content:
308
+ continue
309
+ try:
310
+ verdict = judge.judge_turn(
311
+ interaction=interaction,
312
+ session_id=session_id,
313
+ agent_version=agent_version,
314
+ rng=rng,
315
+ )
316
+ except Exception as exc: # noqa: BLE001 — judge failure must not abort batch
317
+ logger.warning(
318
+ "F1 shadow_comparison dispatch failed for interaction %s: %s",
319
+ interaction.interaction_id,
320
+ exc,
321
+ )
322
+ continue
323
+ if verdict is None:
324
+ continue
325
+ try:
326
+ storage.save_shadow_comparison_verdict(verdict)
327
+ saved_count += 1
328
+ except Exception as exc: # noqa: BLE001 — single-row save failure must not abort batch
329
+ logger.warning(
330
+ "F1 shadow_comparison verdict save failed for interaction %s: %s",
331
+ interaction.interaction_id,
332
+ exc,
333
+ )
334
+
335
+ if saved_count:
336
+ logger.info(
337
+ "F1: saved %d shadow_comparison verdict(s) for session=%s",
338
+ saved_count,
339
+ session_id,
340
+ )