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,689 @@
1
+ from __future__ import annotations
2
+
3
+ import contextvars
4
+ import logging
5
+ import os
6
+ import threading
7
+ import time
8
+ import uuid
9
+ from collections.abc import Callable
10
+ from concurrent.futures import ThreadPoolExecutor
11
+ from concurrent.futures import TimeoutError as FuturesTimeoutError
12
+ from dataclasses import dataclass, field
13
+ from typing import TYPE_CHECKING
14
+
15
+ from reflexio.defaults import resolve_agent_version
16
+ from reflexio.models.api_schema.service_schemas import (
17
+ Interaction,
18
+ PublishUserInteractionRequest,
19
+ Request,
20
+ )
21
+ from reflexio.models.config_schema import Config
22
+ from reflexio.server.api_endpoints.request_context import RequestContext
23
+ from reflexio.server.llm.litellm_client import LiteLLMClient
24
+ from reflexio.server.services.agent_success_evaluation.delayed_group_evaluator import (
25
+ GroupEvaluationScheduler,
26
+ )
27
+ from reflexio.server.services.agent_success_evaluation.group_evaluation_runner import (
28
+ run_group_evaluation,
29
+ )
30
+ from reflexio.server.services.operation_state_utils import OperationStateManager
31
+ from reflexio.server.services.playbook.playbook_generation_service import (
32
+ PlaybookGenerationService,
33
+ )
34
+ from reflexio.server.services.playbook.playbook_service_utils import (
35
+ PlaybookGenerationRequest,
36
+ )
37
+ from reflexio.server.services.profile.profile_generation_service import (
38
+ ProfileGenerationService,
39
+ )
40
+ from reflexio.server.services.profile.profile_generation_service_utils import (
41
+ ProfileGenerationRequest,
42
+ )
43
+ from reflexio.server.services.reflection.reflection_service import ReflectionService
44
+ from reflexio.server.services.reflection.reflection_service_utils import (
45
+ ReflectionServiceRequest,
46
+ )
47
+ from reflexio.server.services.storage.retention import (
48
+ delete_count_for_retention,
49
+ get_row_retention_limits,
50
+ )
51
+ from reflexio.server.tracing import sentry_tags
52
+ from reflexio.server.usage_metrics import record_usage_event
53
+
54
+ if TYPE_CHECKING:
55
+ from reflexio.server.services.unified_search_service import UnifiedSearchService
56
+
57
+ logger = logging.getLogger(__name__)
58
+ # Stale lock timeout - if cleanup started > 10 min ago and still "in_progress", assume it crashed
59
+ CLEANUP_STALE_LOCK_SECONDS = 600
60
+ # Timeout for the outer generation service parallel execution
61
+ GENERATION_SERVICE_TIMEOUT_SECONDS = 600
62
+ _STALL_WARNING_PREFIX = "Reflexio learning is paused"
63
+
64
+
65
+ def _retention_cleanup_interval_seconds() -> float:
66
+ raw = os.getenv("REFLEXIO_RETENTION_CLEANUP_INTERVAL_SECONDS", "300") or "300"
67
+ try:
68
+ return max(0.0, float(raw))
69
+ except ValueError:
70
+ logger.warning(
71
+ "Invalid REFLEXIO_RETENTION_CLEANUP_INTERVAL_SECONDS=%r; using 300",
72
+ raw,
73
+ )
74
+ return 300.0
75
+
76
+
77
+ _RETENTION_CLEANUP_INTERVAL_SECONDS = _retention_cleanup_interval_seconds()
78
+ _retention_cleanup_last_run: dict[tuple[str, str], float] = {}
79
+ _retention_cleanup_lock = threading.Lock()
80
+
81
+
82
+ @dataclass
83
+ class GenerationServiceResult:
84
+ """Result of a GenerationService.run call.
85
+
86
+ Exposes the internally generated request_id plus any warnings so callers
87
+ (CLI, API) can report back to users where their publish landed.
88
+
89
+ Attributes:
90
+ request_id (str | None): The UUID assigned to this publish call, or
91
+ None when ``run()`` returned early before generating one (e.g.
92
+ empty request, missing ``user_id``, or no interactions).
93
+ warnings (list[str]): Non-fatal warnings raised by individual
94
+ generation services during the run.
95
+ """
96
+
97
+ request_id: str | None = None
98
+ warnings: list[str] = field(default_factory=list)
99
+
100
+
101
+ class GenerationService:
102
+ """
103
+ Main service for orchestrating profile, playbook, and agent success evaluation generation.
104
+
105
+ This service coordinates multiple generation services (profile, playbook, agent success)
106
+ and manages the overall interaction processing workflow.
107
+ """
108
+
109
+ def __init__(
110
+ self,
111
+ llm_client: LiteLLMClient,
112
+ request_context: RequestContext,
113
+ ) -> None:
114
+ """
115
+ Initialize the generation service.
116
+
117
+ Args:
118
+ llm_client: Pre-configured LLM client for making API calls.
119
+ request_context: Request context with storage and configurator.
120
+ """
121
+ self.client = llm_client
122
+ self.storage = request_context.storage
123
+ self.org_id = request_context.org_id
124
+ self.configurator = request_context.configurator
125
+ self.request_context = request_context
126
+
127
+ # ===============================
128
+ # public methods
129
+ # ===============================
130
+
131
+ def run(
132
+ self, publish_user_interaction_request: PublishUserInteractionRequest
133
+ ) -> GenerationServiceResult:
134
+ """
135
+ Process a user interaction request by storing interactions and triggering generation services.
136
+
137
+ Profile and playbook generation services run inline in parallel. Agent success
138
+ evaluation is deferred via GroupEvaluationScheduler when a session_id is present,
139
+ so the full session can be evaluated after a period of inactivity.
140
+
141
+ Each generation service (profile, playbook) handles its own:
142
+ - Data collection based on extractor-specific configs
143
+ - Stride checking based on extractor-specific settings
144
+ - Operation state tracking per extractor
145
+
146
+ Args:
147
+ publish_user_interaction_request: The incoming user interaction request
148
+
149
+ Returns:
150
+ GenerationServiceResult: The request_id assigned to this publish call
151
+ and any non-fatal warnings raised by individual generation services.
152
+ """
153
+ result = GenerationServiceResult()
154
+
155
+ if not publish_user_interaction_request:
156
+ logger.error("Received None publish_user_interaction_request")
157
+ return result
158
+
159
+ user_id = publish_user_interaction_request.user_id
160
+ if not user_id:
161
+ logger.error("Received None user_id in publish_user_interaction_request")
162
+ return result
163
+
164
+ # Check if cleanup is needed before adding new interactions.
165
+ self._cleanup_storage_tables_if_needed()
166
+
167
+ publish_start = time.perf_counter()
168
+ # Resolve agent_version: explicit > env var > default. Resolved here
169
+ # (before the try) so success and failure telemetry share the same value.
170
+ agent_version = resolve_agent_version(
171
+ publish_user_interaction_request.agent_version
172
+ )
173
+
174
+ try:
175
+ # Always generate a new UUID for request_id
176
+ request_id = str(uuid.uuid4())
177
+ result.request_id = request_id
178
+
179
+ new_interactions: list[Interaction] = (
180
+ GenerationService.get_interaction_from_publish_user_interaction_request(
181
+ publish_user_interaction_request, request_id
182
+ )
183
+ )
184
+
185
+ if not new_interactions:
186
+ logger.info(
187
+ "No interactions from the publish user interaction request: %s, get all interactions for the user: %s",
188
+ request_id,
189
+ user_id,
190
+ )
191
+ return result
192
+
193
+ record_usage_event(
194
+ org_id=self.org_id,
195
+ user_id=user_id,
196
+ request_id=request_id,
197
+ session_id=publish_user_interaction_request.session_id or None,
198
+ source=publish_user_interaction_request.source,
199
+ agent_version=agent_version,
200
+ event_name="publish_request_received",
201
+ event_category="publish",
202
+ outcome="received",
203
+ count_value=len(new_interactions),
204
+ )
205
+
206
+ # Store Request — propagate customer-stamped metadata so the
207
+ # eval pipeline (e.g. F2 sticky-group aggregator) can read it
208
+ # back from the first request of each session.
209
+ new_request = Request(
210
+ request_id=request_id,
211
+ user_id=user_id,
212
+ source=publish_user_interaction_request.source,
213
+ agent_version=agent_version,
214
+ session_id=publish_user_interaction_request.session_id or None,
215
+ metadata=publish_user_interaction_request.metadata,
216
+ )
217
+ self.storage.add_request(new_request) # type: ignore[reportOptionalMemberAccess]
218
+
219
+ # Add interactions to storage (bulk insert with batched embedding generation)
220
+ self.storage.add_user_interactions_bulk( # type: ignore[reportOptionalMemberAccess]
221
+ user_id=user_id, interactions=new_interactions
222
+ )
223
+
224
+ # Extract source (empty string treated as None)
225
+ source = publish_user_interaction_request.source or None
226
+
227
+ if (
228
+ not publish_user_interaction_request.override_learning_stall
229
+ and (stall_warning := self._active_learning_stall_warning()) is not None
230
+ ):
231
+ result.warnings.append(stall_warning)
232
+ logger.warning("%s; skipping automatic extraction", stall_warning)
233
+ record_usage_event(
234
+ org_id=self.org_id,
235
+ user_id=user_id,
236
+ request_id=request_id,
237
+ session_id=new_request.session_id,
238
+ source=source,
239
+ agent_version=agent_version,
240
+ event_name="publish_request_succeeded",
241
+ event_category="publish",
242
+ outcome="success",
243
+ count_value=len(new_interactions),
244
+ duration_ms=int((time.perf_counter() - publish_start) * 1000),
245
+ metadata={"warning_count": len(result.warnings)},
246
+ )
247
+ return result
248
+
249
+ # Reflection runs as its own sliding-window step BEFORE the
250
+ # extractor pool spins up, so any replacements it makes are
251
+ # visible to the extractors when they retrieve existing
252
+ # profile/playbook context. Wrapped in a broad except so a
253
+ # reflection bug never breaks the publish.
254
+ self._maybe_run_reflection(
255
+ user_id=user_id, agent_version=agent_version, source=source
256
+ )
257
+
258
+ # Create generation services and requests
259
+ # Each service writes to separate storage tables and has no dependencies on others
260
+ profile_generation_service = ProfileGenerationService(
261
+ llm_client=self.client, request_context=self.request_context
262
+ )
263
+ profile_generation_request = ProfileGenerationRequest(
264
+ user_id=user_id,
265
+ request_id=request_id,
266
+ source=source,
267
+ force_extraction=publish_user_interaction_request.force_extraction,
268
+ )
269
+
270
+ playbook_generation_service = PlaybookGenerationService(
271
+ llm_client=self.client,
272
+ request_context=self.request_context,
273
+ skip_aggregation=publish_user_interaction_request.skip_aggregation,
274
+ )
275
+ playbook_generation_request = PlaybookGenerationRequest(
276
+ request_id=request_id,
277
+ agent_version=agent_version,
278
+ user_id=user_id,
279
+ source=source,
280
+ force_extraction=publish_user_interaction_request.force_extraction,
281
+ )
282
+
283
+ # Run profile and playbook generation services in parallel
284
+ # Each service creates its own internal ThreadPoolExecutor for extractors
285
+ # This is safe because we create separate, independent pool instances
286
+ # Uses manual executor management to avoid blocking on shutdown(wait=True)
287
+ # when threads are hung on LLM calls
288
+ executor = ThreadPoolExecutor(max_workers=2)
289
+ try:
290
+ # Each thread needs its own context copy — Context.run() is non-reentrant
291
+ futures = [
292
+ executor.submit(
293
+ contextvars.copy_context().run,
294
+ profile_generation_service.run,
295
+ profile_generation_request,
296
+ ),
297
+ executor.submit(
298
+ contextvars.copy_context().run,
299
+ playbook_generation_service.run,
300
+ playbook_generation_request,
301
+ ),
302
+ ]
303
+
304
+ # Collect results and handle any exceptions
305
+ # Each service failure is logged but doesn't block others
306
+ service_names = ["profile_generation", "playbook_generation"]
307
+ for future, service_name in zip(futures, service_names, strict=True):
308
+ try:
309
+ future.result(timeout=GENERATION_SERVICE_TIMEOUT_SECONDS)
310
+ except FuturesTimeoutError: # noqa: PERF203
311
+ msg = f"{service_name} timed out after {GENERATION_SERVICE_TIMEOUT_SECONDS}s"
312
+ with sentry_tags(
313
+ subsystem="generation",
314
+ service=service_name,
315
+ request_id=request_id,
316
+ error_type="timeout",
317
+ ):
318
+ logger.error("%s for request %s", msg, request_id)
319
+ result.warnings.append(msg)
320
+ except Exception as e:
321
+ msg = f"{service_name} failed: {e}"
322
+ with sentry_tags(
323
+ subsystem="generation",
324
+ service=service_name,
325
+ request_id=request_id,
326
+ error_type=type(e).__name__,
327
+ ):
328
+ logger.exception(
329
+ "Generation service failed for request %s", request_id,
330
+ )
331
+ result.warnings.append(msg)
332
+ finally:
333
+ executor.shutdown(wait=False, cancel_futures=True)
334
+
335
+ # Schedule delayed group evaluation if session_id is present
336
+ self._schedule_group_evaluation_if_needed(
337
+ new_request=new_request,
338
+ user_id=user_id,
339
+ agent_version=agent_version,
340
+ source=source,
341
+ )
342
+
343
+ record_usage_event(
344
+ org_id=self.org_id,
345
+ user_id=user_id,
346
+ request_id=request_id,
347
+ session_id=new_request.session_id,
348
+ source=source,
349
+ agent_version=agent_version,
350
+ backend="classic",
351
+ event_name="publish_request_succeeded",
352
+ event_category="publish",
353
+ outcome="success",
354
+ count_value=len(new_interactions),
355
+ duration_ms=int((time.perf_counter() - publish_start) * 1000),
356
+ metadata={"warning_count": len(result.warnings)},
357
+ )
358
+ return result
359
+
360
+ except Exception as e:
361
+ record_usage_event(
362
+ org_id=self.org_id,
363
+ user_id=user_id,
364
+ request_id=result.request_id,
365
+ session_id=publish_user_interaction_request.session_id or None,
366
+ source=publish_user_interaction_request.source,
367
+ agent_version=agent_version,
368
+ event_name="publish_request_failed",
369
+ event_category="publish",
370
+ outcome="failed",
371
+ duration_ms=int((time.perf_counter() - publish_start) * 1000),
372
+ error_kind=type(e).__name__,
373
+ )
374
+ with sentry_tags(
375
+ subsystem="generation",
376
+ op="refresh_profile",
377
+ org_id=self.org_id,
378
+ user_id=user_id,
379
+ request_id=result.request_id,
380
+ error_type=type(e).__name__,
381
+ ):
382
+ logger.exception(
383
+ "Failed to refresh user profile for user id: %s", user_id,
384
+ )
385
+ raise
386
+
387
+ # ===============================
388
+ # private methods
389
+ # ===============================
390
+
391
+ def _schedule_group_evaluation_if_needed(
392
+ self,
393
+ *,
394
+ new_request: Request,
395
+ user_id: str,
396
+ agent_version: str,
397
+ source: str | None,
398
+ ) -> None:
399
+ """Enqueue agent-success evaluation for this session, if session_id is set.
400
+
401
+ Must be called once per publish — from BOTH the classic and the agentic
402
+ extraction code paths — so that ``AgentSuccessEvaluationResult`` records
403
+ get produced regardless of which backend is in use. Skipping this for
404
+ the agentic path was the silent root cause of empty /evaluations tiles.
405
+
406
+ Args:
407
+ new_request (Request): The just-stored request whose session is being
408
+ published into. ``new_request.session_id`` gates scheduling.
409
+ user_id (str): The user owning the session.
410
+ agent_version (str): Agent version string carried into the evaluator.
411
+ source (str | None): Optional source label.
412
+ """
413
+ session_id = new_request.session_id
414
+ if not session_id:
415
+ return
416
+
417
+ scheduler = GroupEvaluationScheduler.get_instance()
418
+ key = (self.org_id, user_id, session_id)
419
+
420
+ def make_callback(
421
+ _org_id: str,
422
+ _user_id: str,
423
+ _sid: str,
424
+ _av: str,
425
+ _src: str | None,
426
+ _rc: RequestContext,
427
+ _llm: LiteLLMClient,
428
+ ) -> Callable[[], None]:
429
+ def callback() -> None:
430
+ run_group_evaluation(
431
+ org_id=_org_id,
432
+ user_id=_user_id,
433
+ session_id=_sid,
434
+ agent_version=_av,
435
+ source=_src,
436
+ request_context=_rc,
437
+ llm_client=_llm,
438
+ )
439
+
440
+ return callback
441
+
442
+ scheduler.schedule(
443
+ key,
444
+ make_callback(
445
+ self.org_id,
446
+ user_id,
447
+ session_id,
448
+ agent_version,
449
+ source,
450
+ self.request_context,
451
+ self.client,
452
+ ),
453
+ )
454
+
455
+ def _maybe_run_reflection(
456
+ self, *, user_id: str, agent_version: str, source: str | None
457
+ ) -> None:
458
+ """Best-effort reflection pass before extraction.
459
+
460
+ Any failure is caught and logged so the surrounding publish
461
+ flow (extraction + delayed evaluation) is unaffected.
462
+ """
463
+ try:
464
+ service = ReflectionService(
465
+ request_context=self.request_context,
466
+ llm_client=self.client,
467
+ )
468
+ service.run(
469
+ ReflectionServiceRequest(
470
+ user_id=user_id,
471
+ agent_version=agent_version,
472
+ source=source,
473
+ )
474
+ )
475
+ except Exception as exc: # noqa: BLE001 — must not break publish
476
+ # Promoted to logger.exception so Sentry's LoggingIntegration
477
+ # captures the event. The except still doesn't re-raise — the
478
+ # publish loop continues — but on-call now sees the failure
479
+ # instead of it being buried at WARNING level.
480
+ with sentry_tags(
481
+ subsystem="generation",
482
+ op="reflection",
483
+ org_id=self.org_id,
484
+ user_id=user_id,
485
+ error_type=type(exc).__name__,
486
+ ):
487
+ logger.exception("reflection step failed for user %s", user_id)
488
+
489
+ def _cleanup_storage_tables_if_needed(self) -> None:
490
+ """Best-effort publish-boundary cleanup for capped storage tables."""
491
+ now = time.monotonic()
492
+ limits = {
493
+ target_name: limit
494
+ for target_name, limit in get_row_retention_limits().items()
495
+ if limit > 0 and self._should_check_retention_target(target_name, now)
496
+ }
497
+ if not limits:
498
+ return
499
+
500
+ try:
501
+ mgr = OperationStateManager(
502
+ self.storage, # type: ignore[reportArgumentType]
503
+ self.org_id,
504
+ "storage_table_cleanup", # type: ignore[reportArgumentType]
505
+ )
506
+ if not mgr.acquire_simple_lock(stale_seconds=CLEANUP_STALE_LOCK_SECONDS):
507
+ return
508
+
509
+ try:
510
+ for target_name, limit in limits.items():
511
+ # Isolate per-target failures so one bad table does not
512
+ # short-circuit cleanup for every subsequent target.
513
+ try:
514
+ self._cleanup_retention_target(target_name, limit)
515
+ except Exception as e: # noqa: BLE001
516
+ with sentry_tags(
517
+ subsystem="generation",
518
+ op="cleanup_retention_target",
519
+ org_id=self.org_id,
520
+ target_name=target_name,
521
+ error_type=type(e).__name__,
522
+ ):
523
+ logger.exception(
524
+ "Failed to cleanup retention target %s", target_name,
525
+ )
526
+ finally:
527
+ mgr.release_simple_lock()
528
+
529
+ except Exception as e:
530
+ with sentry_tags(
531
+ subsystem="generation",
532
+ op="cleanup_storage_tables",
533
+ org_id=self.org_id,
534
+ error_type=type(e).__name__,
535
+ ):
536
+ logger.exception("Failed to cleanup storage tables")
537
+ # Don't raise - cleanup failure shouldn't block normal operation
538
+
539
+ def _should_check_retention_target(self, target_name: str, now: float) -> bool:
540
+ if _RETENTION_CLEANUP_INTERVAL_SECONDS <= 0:
541
+ return True
542
+ key = (self.org_id, target_name)
543
+ with _retention_cleanup_lock:
544
+ last_run = _retention_cleanup_last_run.get(key)
545
+ if (
546
+ last_run is not None
547
+ and now - last_run < _RETENTION_CLEANUP_INTERVAL_SECONDS
548
+ ):
549
+ return False
550
+ _retention_cleanup_last_run[key] = now
551
+ return True
552
+
553
+ def _active_learning_stall_warning(self) -> str | None:
554
+ """Return a warning when extraction should not auto-retry.
555
+
556
+ Plugin publishes should still store raw interactions while the local
557
+ LLM provider is blocked by auth or billing, but they
558
+ must not keep invoking extraction on every publish. Only callers that
559
+ pass ``override_learning_stall=True`` bypass this check so an explicit
560
+ retry after reauth can clear the stall state on a successful provider
561
+ call.
562
+ """
563
+ try:
564
+ stall_state = self.storage.get_stall_state() # type: ignore[reportOptionalMemberAccess]
565
+ except (AttributeError, NotImplementedError):
566
+ return None
567
+ except Exception as exc: # noqa: BLE001 - stall telemetry must not block publish.
568
+ logger.debug("Failed to read stall_state before extraction: %s", exc)
569
+ return None
570
+
571
+ if not getattr(stall_state, "stalled", False):
572
+ return None
573
+ reason = getattr(stall_state, "reason", None) or "unknown"
574
+ suffix = (
575
+ "reauthenticate the active coding-agent provider, then run an explicit "
576
+ "override retry to resume."
577
+ if reason == "auth_error"
578
+ else "wait for the limit/reset condition to clear, then run an explicit "
579
+ "override retry to resume."
580
+ )
581
+ return f"{_STALL_WARNING_PREFIX} ({reason}); {suffix}"
582
+
583
+ def _cleanup_retention_target(self, target_name: str, limit: int) -> None:
584
+ total_count = self.storage.count_retention_target_rows(target_name) # type: ignore[reportOptionalMemberAccess]
585
+ if total_count < limit:
586
+ return
587
+ delete_count = delete_count_for_retention(total_count)
588
+ deleted = self.storage.delete_oldest_retention_target_rows( # type: ignore[reportOptionalMemberAccess]
589
+ target_name,
590
+ delete_count,
591
+ )
592
+ logger.info(
593
+ "Cleaned up %d oldest %s row(s) (total was %d, limit %d)",
594
+ deleted,
595
+ target_name,
596
+ total_count,
597
+ limit,
598
+ )
599
+
600
+ # ===============================
601
+ # static methods
602
+ # ===============================
603
+
604
+ @staticmethod
605
+ def get_interaction_from_publish_user_interaction_request(
606
+ publish_user_interaction_request: PublishUserInteractionRequest,
607
+ request_id: str,
608
+ ) -> list[Interaction]:
609
+ """get interaction from publish user interaction request
610
+
611
+ Args:
612
+ publish_user_interaction_request (PublishUserInteractionRequest): The publish user interaction request
613
+ request_id (str): The request ID generated by the service
614
+
615
+ Returns:
616
+ list[Interaction]: List of interactions created from the request
617
+ """
618
+ interaction_data_list = publish_user_interaction_request.interaction_data_list
619
+
620
+ user_id = publish_user_interaction_request.user_id
621
+ # Honor the client-provided ``created_at`` — InteractionData defaults
622
+ # it to client-side ``now()`` on construction, so it's always populated.
623
+ # Apps that publish backdated conversations (e.g., a benchmark replay
624
+ # of 2023 chats run in 2026) need the wall-clock time preserved so the
625
+ # extraction agent has a real temporal anchor for relative-time
626
+ # references like "X weeks ago" / "yesterday". Stamping server-now here
627
+ # would erase that anchor and force every event onto today's date.
628
+ return [
629
+ Interaction(
630
+ # interaction_id is auto-generated by DB
631
+ user_id=user_id,
632
+ request_id=request_id,
633
+ created_at=interaction_data.created_at,
634
+ content=interaction_data.content,
635
+ role=interaction_data.role,
636
+ user_action=interaction_data.user_action,
637
+ user_action_description=interaction_data.user_action_description,
638
+ interacted_image_url=interaction_data.interacted_image_url,
639
+ image_encoding=interaction_data.image_encoding,
640
+ shadow_content=interaction_data.shadow_content,
641
+ expert_content=interaction_data.expert_content,
642
+ tools_used=interaction_data.tools_used,
643
+ citations=interaction_data.citations,
644
+ )
645
+ for interaction_data in interaction_data_list
646
+ ]
647
+
648
+
649
+ def build_extraction_service(
650
+ config: Config,
651
+ *,
652
+ llm_client: LiteLLMClient,
653
+ request_context: RequestContext,
654
+ ) -> ProfileGenerationService:
655
+ """Return the profile extraction service.
656
+
657
+ Args:
658
+ config (Config): Top-level ``Config`` (unused; kept for API consistency).
659
+ llm_client (LiteLLMClient): Configured ``LiteLLMClient``.
660
+ request_context (RequestContext): Current request context.
661
+
662
+ Returns:
663
+ ProfileGenerationService: Classic profile extraction service.
664
+ """
665
+ del config # unused — agentic path bypasses this factory
666
+ return ProfileGenerationService(
667
+ llm_client=llm_client, request_context=request_context
668
+ )
669
+
670
+
671
+ def build_search_service(
672
+ config: Config, # noqa: ARG001
673
+ *,
674
+ llm_client: LiteLLMClient,
675
+ request_context: RequestContext,
676
+ ) -> UnifiedSearchService:
677
+ """Build the unified search service.
678
+
679
+ Args:
680
+ config (Config): Top-level ``Config`` (unused; kept for API consistency).
681
+ llm_client (LiteLLMClient): Configured ``LiteLLMClient``.
682
+ request_context (RequestContext): Current request context.
683
+
684
+ Returns:
685
+ A ``UnifiedSearchService`` holding ``llm_client`` and ``request_context``.
686
+ """
687
+ from reflexio.server.services.unified_search_service import UnifiedSearchService
688
+
689
+ return UnifiedSearchService(llm_client=llm_client, request_context=request_context)