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,28 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen=True)
5
+ class PlaybookServiceConstants:
6
+ PLAYBOOK_EXTRACTORS_CONFIG_NAME = "user_playbook_extractor_config"
7
+ # ===============================
8
+ # prompt ids
9
+ # ===============================
10
+ PLAYBOOK_SHOULD_GENERATE_PROMPT_ID = "playbook_should_generate"
11
+ PLAYBOOK_EXTRACTION_CONTEXT_PROMPT_ID = "playbook_extraction_context"
12
+ PLAYBOOK_EXTRACTION_PROMPT_ID = "playbook_extraction_main"
13
+ PLAYBOOK_AGGREGATION_PROMPT_ID = "playbook_aggregation"
14
+
15
+ # ===============================
16
+ # expert content prompt ids
17
+ # ===============================
18
+ PLAYBOOK_SHOULD_GENERATE_EXPERT_PROMPT_ID = "playbook_should_generate_expert"
19
+ PLAYBOOK_EXTRACTION_CONTEXT_EXPERT_PROMPT_ID = "playbook_extraction_context_expert"
20
+ PLAYBOOK_EXTRACTION_EXPERT_PROMPT_ID = "playbook_extraction_main_expert"
21
+
22
+ # ===============================
23
+ # agent success evaluation prompt ids
24
+ # ===============================
25
+ AGENT_SUCCESS_EVALUATION_SHOULD_EVALUATE_PROMPT_ID = (
26
+ "agent_success_evaluation_should_evaluate"
27
+ )
28
+ AGENT_SUCCESS_EVALUATION_PROMPT_ID = "agent_success_evaluation"
@@ -0,0 +1,362 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
7
+
8
+ from reflexio.models.api_schema.domain.entities import Interaction
9
+ from reflexio.models.api_schema.internal_schema import RequestInteractionDataModel
10
+ from reflexio.server.prompt.prompt_manager import PromptManager
11
+ from reflexio.server.services.playbook.playbook_service_constants import (
12
+ PlaybookServiceConstants,
13
+ )
14
+ from reflexio.server.services.service_utils import (
15
+ MessageConstructionConfig,
16
+ PromptConfig,
17
+ construct_messages_from_interactions,
18
+ extract_interactions_from_request_interaction_data_models,
19
+ format_sessions_to_history_string,
20
+ )
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # ===============================
25
+ # Pydantic classes for playbook_extraction_main prompt output schema
26
+ # ===============================
27
+
28
+
29
+ class StructuredPlaybookContent(BaseModel):
30
+ """
31
+ Structured representation of a single playbook entry from LLM output.
32
+
33
+ Field order matters for autoregressive conditioning: rationale is generated
34
+ first, then trigger, then content is synthesized last as a summary.
35
+
36
+ The extraction schema intentionally does not ask the model to emit a
37
+ polarity label. The extractor writes action rules or avoidance rules, and
38
+ the service derives the internal :class:`UserPlaybook` polarity from that
39
+ wording before storage.
40
+ """
41
+
42
+ rationale: str | None = Field(
43
+ default=None,
44
+ description="The reasoning behind this playbook entry — generated first for autoregressive conditioning",
45
+ )
46
+ trigger: str | None = Field(
47
+ default=None,
48
+ description="The condition or context when this rule applies",
49
+ )
50
+ content: str | None = Field(
51
+ default=None,
52
+ description="The main actionable content of the playbook entry — what to do or what to avoid",
53
+ )
54
+ source_span: str | None = Field(
55
+ default=None,
56
+ description="Verbatim excerpt from the source that most directly supports this playbook entry",
57
+ )
58
+ notes: str | None = Field(
59
+ default=None,
60
+ description="Free-form extraction notes — confidence, caveats, or alternative readings",
61
+ )
62
+ reader_angle: str | None = Field(
63
+ default=None,
64
+ description="The extraction perspective or reader role that surfaced this entry",
65
+ )
66
+ model_config = ConfigDict(
67
+ extra="allow",
68
+ json_schema_extra={"additionalProperties": False},
69
+ )
70
+
71
+ @property
72
+ def is_structured(self) -> bool:
73
+ """Check if this playbook entry has both a trigger and content."""
74
+ return bool(
75
+ self.trigger
76
+ and self.trigger.strip()
77
+ and self.content
78
+ and self.content.strip()
79
+ )
80
+
81
+ @property
82
+ def has_content(self) -> bool:
83
+ """Check if this output contains actual content."""
84
+ return bool(self.content and self.content.strip())
85
+
86
+
87
+ class StructuredPlaybookList(BaseModel):
88
+ """
89
+ Wrapper schema for extracting zero or more playbook entries in a single LLM call.
90
+
91
+ The canonical shape is ``{"playbooks": [...]}``. An empty list means the model
92
+ found no valid SOPs in the window. This wrapper exists because OpenAI structured
93
+ output requires a JSON object at the root, so ``list[StructuredPlaybookContent]``
94
+ cannot be used directly as ``response_format``.
95
+ """
96
+
97
+ playbooks: list[StructuredPlaybookContent] = Field(
98
+ default_factory=list,
99
+ description="Extracted playbook entries — empty list when no valid SOP was found",
100
+ )
101
+
102
+ model_config = ConfigDict(
103
+ extra="forbid",
104
+ json_schema_extra={"additionalProperties": False},
105
+ )
106
+
107
+
108
+ class PlaybookAggregationOutput(BaseModel):
109
+ """
110
+ Output schema for the playbook_aggregation prompt.
111
+
112
+ Contains the consolidated playbook entry or null if no new entry should be generated
113
+ (e.g., when it duplicates existing approved playbook).
114
+ """
115
+
116
+ playbook: StructuredPlaybookContent | None = Field(
117
+ default=None,
118
+ description="The consolidated playbook entry, or null if no new entry should be generated",
119
+ )
120
+
121
+ @model_validator(mode="before")
122
+ @classmethod
123
+ def normalize_wrapper_key(cls, data: Any) -> Any:
124
+ """Accept both 'playbook' and legacy 'feedback' as the wrapper key."""
125
+ if isinstance(data, dict) and "feedback" in data and "playbook" not in data:
126
+ data["playbook"] = data.pop("feedback")
127
+ return data
128
+
129
+ model_config = ConfigDict(
130
+ extra="allow",
131
+ json_schema_extra={"additionalProperties": False},
132
+ )
133
+
134
+
135
+ def format_structured_fields_for_display(
136
+ structured: StructuredPlaybookContent,
137
+ ) -> str:
138
+ """
139
+ Format structured metadata fields for display/debug purposes.
140
+
141
+ This is NOT for producing content values. Use ensure_playbook_content()
142
+ when you need to obtain the freeform content string.
143
+
144
+ Args:
145
+ structured (StructuredPlaybookContent): The structured playbook content
146
+
147
+ Returns:
148
+ str: Formatted structured fields string for display
149
+ """
150
+ lines = []
151
+
152
+ if structured.trigger:
153
+ lines.append(f'Trigger: "{structured.trigger}"')
154
+
155
+ if structured.rationale:
156
+ lines.append(f'Rationale: "{structured.rationale}"')
157
+
158
+ if not lines and structured.content:
159
+ return structured.content
160
+
161
+ return "\n".join(lines)
162
+
163
+
164
+ def ensure_playbook_content(
165
+ playbook_content: str | None,
166
+ structured: StructuredPlaybookContent,
167
+ ) -> str:
168
+ """
169
+ Return playbook_content if present; legacy fallback from structured fields.
170
+
171
+ Args:
172
+ playbook_content (str | None): The freeform content from the LLM
173
+ structured (StructuredPlaybookContent): Structured fields for fallback
174
+
175
+ Returns:
176
+ str: The freeform playbook_content, or a formatted fallback from structured fields.
177
+ """
178
+ if playbook_content and playbook_content.strip():
179
+ return playbook_content
180
+ return format_structured_fields_for_display(structured)
181
+
182
+
183
+ class PlaybookGenerationRequest(BaseModel):
184
+ request_id: str
185
+ agent_version: str
186
+ user_id: str | None = None # for per-user playbook extraction
187
+ source: str | None = None
188
+ rerun_start_time: int | None = None # Unix timestamp for rerun flows
189
+ rerun_end_time: int | None = None # Unix timestamp for rerun flows
190
+ auto_run: bool = (
191
+ True # True for regular flow (checks stride_size), False for rerun/manual
192
+ )
193
+ force_extraction: bool = False # when True, bypass all extraction gates (stride_size, cheap pre-filter, LLM should_run)
194
+
195
+
196
+ class PlaybookAggregatorRequest(BaseModel):
197
+ agent_version: str
198
+ rerun: bool = False
199
+
200
+
201
+ def construct_playbook_extraction_messages_from_sessions(
202
+ prompt_manager: PromptManager,
203
+ request_interaction_data_models: list[RequestInteractionDataModel],
204
+ agent_context_prompt: str,
205
+ extraction_definition_prompt: str,
206
+ tool_can_use: str | None = None,
207
+ ) -> list[dict]:
208
+ """
209
+ Construct LLM messages for playbook extraction from sessions.
210
+
211
+ This function uses the shared message construction interface to build messages
212
+ with a system prompt and a final user prompt specific to playbook extraction.
213
+
214
+ Args:
215
+ prompt_manager: The prompt manager for rendering prompt templates
216
+ request_interaction_data_models: List of request interaction groups to extract playbook entries from
217
+ agent_context_prompt: Context about the agent for system message
218
+ extraction_definition_prompt: Definition of what the playbook should contain
219
+ tool_can_use: Optional formatted string of tools available to the agent
220
+
221
+ Returns:
222
+ list[dict]: List of messages ready for playbook extraction
223
+ """
224
+ # Configure system message (before interactions)
225
+ # Stable content (instructions, examples, definitions) goes in system message for token caching
226
+ system_config = PromptConfig(
227
+ prompt_id=PlaybookServiceConstants.PLAYBOOK_EXTRACTION_CONTEXT_PROMPT_ID,
228
+ variables={
229
+ "agent_context_prompt": agent_context_prompt,
230
+ "extraction_definition_prompt": extraction_definition_prompt,
231
+ "tool_can_use": tool_can_use or "",
232
+ },
233
+ )
234
+
235
+ # Configure final user message (after interactions)
236
+ # Only dynamic per-call data goes in user message
237
+ user_config = PromptConfig(
238
+ prompt_id=PlaybookServiceConstants.PLAYBOOK_EXTRACTION_PROMPT_ID,
239
+ variables={
240
+ "interactions": format_sessions_to_history_string(
241
+ request_interaction_data_models
242
+ ),
243
+ },
244
+ )
245
+
246
+ # Extract flat interactions for message construction
247
+ interactions = extract_interactions_from_request_interaction_data_models(
248
+ request_interaction_data_models
249
+ )
250
+
251
+ # Use shared message construction
252
+ config = MessageConstructionConfig(
253
+ prompt_manager=prompt_manager,
254
+ system_prompt_config=system_config,
255
+ user_prompt_config=user_config,
256
+ )
257
+
258
+ return construct_messages_from_interactions(interactions, config)
259
+
260
+
261
+ # ===============================
262
+ # Expert content utilities
263
+ # ===============================
264
+
265
+
266
+ def has_expert_content(interactions: list[Interaction]) -> bool:
267
+ """Check if any interaction has non-empty expert_content."""
268
+ return any(i.expert_content for i in interactions)
269
+
270
+
271
+ def format_expert_comparison_pairs(
272
+ request_interaction_data_models: list[RequestInteractionDataModel],
273
+ ) -> str:
274
+ """
275
+ Format interactions with expert_content as agent-vs-expert comparison blocks.
276
+
277
+ For each agent interaction that has expert_content, includes the preceding user
278
+ question for context, the agent's actual response, and the expert's ideal response.
279
+
280
+ Args:
281
+ request_interaction_data_models: Session data models containing interactions
282
+
283
+ Returns:
284
+ str: Formatted comparison pairs string
285
+ """
286
+ interactions = extract_interactions_from_request_interaction_data_models(
287
+ request_interaction_data_models
288
+ )
289
+
290
+ pairs: list[str] = []
291
+ pair_num = 0
292
+ for i, interaction in enumerate(interactions):
293
+ if not interaction.expert_content:
294
+ continue
295
+
296
+ pair_num += 1
297
+ # Find the preceding user question for context
298
+ user_question = ""
299
+ for j in range(i - 1, -1, -1):
300
+ if interactions[j].role.lower() == "user":
301
+ user_question = interactions[j].content
302
+ break
303
+
304
+ parts = [f"=== Comparison {pair_num} ==="]
305
+ if user_question:
306
+ parts.append(f"User Question: ```{user_question}```")
307
+ parts.append(f"Agent Response: ```{interaction.content}```")
308
+ parts.append(f"Expert Response: ```{interaction.expert_content}```")
309
+ pairs.append("\n".join(parts))
310
+
311
+ return "\n\n".join(pairs)
312
+
313
+
314
+ def construct_expert_playbook_extraction_messages(
315
+ prompt_manager: PromptManager,
316
+ request_interaction_data_models: list[RequestInteractionDataModel],
317
+ agent_context_prompt: str,
318
+ extraction_definition_prompt: str,
319
+ ) -> list[dict]:
320
+ """
321
+ Construct LLM messages for expert-content playbook extraction.
322
+
323
+ Uses expert-specific prompts that compare agent responses against expert
324
+ responses and extract playbook entries about alignment gaps.
325
+
326
+ Args:
327
+ prompt_manager: The prompt manager for rendering prompt templates
328
+ request_interaction_data_models: Session data with expert_content interactions
329
+ agent_context_prompt: Context about the agent for system message
330
+ extraction_definition_prompt: Definition of what the playbook should contain
331
+
332
+ Returns:
333
+ list[dict]: List of messages ready for expert playbook extraction
334
+ """
335
+ system_config = PromptConfig(
336
+ prompt_id=PlaybookServiceConstants.PLAYBOOK_EXTRACTION_CONTEXT_EXPERT_PROMPT_ID,
337
+ variables={
338
+ "agent_context_prompt": agent_context_prompt,
339
+ "extraction_definition_prompt": extraction_definition_prompt,
340
+ },
341
+ )
342
+
343
+ comparison_pairs = format_expert_comparison_pairs(request_interaction_data_models)
344
+
345
+ user_config = PromptConfig(
346
+ prompt_id=PlaybookServiceConstants.PLAYBOOK_EXTRACTION_EXPERT_PROMPT_ID,
347
+ variables={
348
+ "comparison_pairs": comparison_pairs,
349
+ },
350
+ )
351
+
352
+ interactions = extract_interactions_from_request_interaction_data_models(
353
+ request_interaction_data_models
354
+ )
355
+
356
+ config = MessageConstructionConfig(
357
+ prompt_manager=prompt_manager,
358
+ system_prompt_config=system_config,
359
+ user_prompt_config=user_config,
360
+ )
361
+
362
+ return construct_messages_from_interactions(interactions, config)
@@ -0,0 +1,24 @@
1
+ """GEPA-driven playbook content optimizer.
2
+
3
+ Top-level entry points exported from this package:
4
+
5
+ - ``PlaybookOptimizer.optimize(target)`` — runs one paired-rollout search
6
+ for a single playbook and persists the result.
7
+ - ``PlaybookOptimizationScheduler.get_instance()`` — singleton that
8
+ debounces enqueues from upstream services (the aggregator and the
9
+ user-playbook generation service) and dispatches each ``optimize`` call
10
+ on a worker thread.
11
+ - ``PlaybookOptimizationTarget`` — the (kind, target_id) pair both APIs
12
+ consume.
13
+
14
+ The full doc lives at ``docs/playbook_optimizer_assistant_backends.md``.
15
+ """
16
+
17
+ from .optimizer import PlaybookOptimizationTarget, PlaybookOptimizer
18
+ from .scheduler import PlaybookOptimizationScheduler
19
+
20
+ __all__ = [
21
+ "PlaybookOptimizationScheduler",
22
+ "PlaybookOptimizationTarget",
23
+ "PlaybookOptimizer",
24
+ ]
@@ -0,0 +1,246 @@
1
+ """Assistant backends for the playbook optimizer.
2
+
3
+ The playbook optimizer runs paired rollouts (incumbent vs candidate playbook)
4
+ against a "real" assistant. This module hosts the two pluggable backends that
5
+ produce the assistant's reply for a given turn:
6
+
7
+ - ``WebhookAssistant`` — POSTs JSON to a configured URL.
8
+ - ``LocalScriptAssistant`` — spawns a subprocess and exchanges JSON via
9
+ stdin/stdout.
10
+
11
+ Both satisfy ``AssistantCallable``, so ``MultiTurnRollout`` and the GEPA
12
+ adapter never need to know which one is in use. Selection happens once in
13
+ ``PlaybookOptimizer._create_assistant`` based on config.
14
+
15
+ Failures from either backend raise ``AssistantFailedError`` (or a subclass);
16
+ the GEPA adapter catches that single base class and turns it into an
17
+ ``aborted`` evaluation row instead of crashing the search loop.
18
+
19
+ The file is named ``assistant_webhook.py`` for historical reasons — the
20
+ local-script backend was added later. New code should still import from this
21
+ module.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import subprocess
28
+ import time
29
+ from typing import Any, Protocol
30
+
31
+ import requests
32
+
33
+ from reflexio.models.api_schema.domain import AgentPlaybook
34
+
35
+ from .models import ChatMessage
36
+
37
+
38
+ class AssistantCallable(Protocol):
39
+ """Shape every assistant backend must satisfy.
40
+
41
+ A backend takes the conversation so far plus the playbook(s) to inject
42
+ and returns the assistant's next reply as a plain string. Errors are
43
+ signalled by raising ``AssistantFailedError`` (or a subclass).
44
+ """
45
+
46
+ def __call__(
47
+ self, messages: list[ChatMessage], playbooks: list[AgentPlaybook]
48
+ ) -> str: ...
49
+
50
+
51
+ class AssistantFailedError(Exception):
52
+ """Base class for any assistant-backend failure.
53
+
54
+ The GEPA adapter catches this single type to absorb backend faults
55
+ (network errors, subprocess crashes, malformed responses) and record
56
+ them as ``verdict='aborted'`` evaluations rather than aborting the
57
+ optimizer run.
58
+ """
59
+
60
+
61
+ class WebhookFailedError(AssistantFailedError):
62
+ """Raised when ``WebhookAssistant`` exhausts its retries."""
63
+
64
+
65
+ class LocalScriptFailedError(AssistantFailedError):
66
+ """Raised when ``LocalScriptAssistant`` exhausts its retries."""
67
+
68
+
69
+ def _build_payload(
70
+ messages: list[ChatMessage], playbooks: list[AgentPlaybook]
71
+ ) -> dict[str, Any]:
72
+ """Build the wire payload shared by both backends.
73
+
74
+ Centralising this guarantees that the webhook body and the script's
75
+ stdin contain the *same* fields in the *same* shape — the only thing
76
+ that differs between the two transports is how the bytes are delivered.
77
+ """
78
+ return {
79
+ "messages": [message.model_dump() for message in messages],
80
+ "playbooks": [
81
+ {
82
+ "id": pb.agent_playbook_id,
83
+ "content": pb.content,
84
+ "trigger": pb.trigger,
85
+ }
86
+ for pb in playbooks
87
+ ],
88
+ }
89
+
90
+
91
+ class WebhookAssistant:
92
+ """HTTP assistant backend.
93
+
94
+ POSTs the rollout payload to ``url`` and expects ``{"content": str}`` in
95
+ the response body. Retries any exception (network error, non-2xx,
96
+ malformed JSON, missing field) with exponential backoff up to
97
+ ``max_retries`` additional attempts before raising
98
+ ``WebhookFailedError``.
99
+
100
+ Args:
101
+ url: Destination URL. The optimizer does not validate the scheme,
102
+ so operators are responsible for ensuring it points at a host
103
+ that satisfies their data-residency requirements.
104
+ auth_header: Sent verbatim as the ``Authorization`` header. Never
105
+ logged.
106
+ timeout_s: Per-request timeout (passed to ``requests.post``).
107
+ max_retries: Number of *additional* attempts after the first try.
108
+ ``max_retries=0`` means a single attempt.
109
+ backoff_base_s: Base for the exponential delay
110
+ ``backoff_base_s * 2**attempt`` between retries.
111
+ """
112
+
113
+ def __init__(
114
+ self,
115
+ url: str,
116
+ auth_header: str | None,
117
+ timeout_s: int,
118
+ max_retries: int,
119
+ backoff_base_s: float,
120
+ ) -> None:
121
+ self.url = url
122
+ self.auth_header = auth_header
123
+ self.timeout_s = timeout_s
124
+ self.max_retries = max_retries
125
+ self.backoff_base_s = backoff_base_s
126
+
127
+ def __call__(
128
+ self, messages: list[ChatMessage], playbooks: list[AgentPlaybook]
129
+ ) -> str:
130
+ headers = {"Content-Type": "application/json"}
131
+ if self.auth_header:
132
+ headers["Authorization"] = self.auth_header
133
+ payload = _build_payload(messages, playbooks)
134
+ last_error: Exception | None = None
135
+ for attempt in range(self.max_retries + 1):
136
+ try:
137
+ response = requests.post(
138
+ self.url,
139
+ json=payload,
140
+ headers=headers,
141
+ timeout=self.timeout_s,
142
+ )
143
+ response.raise_for_status()
144
+ data = response.json()
145
+ content = data.get("content")
146
+ if not isinstance(content, str):
147
+ raise WebhookFailedError("assistant webhook returned no content")
148
+ return content
149
+ except Exception as exc: # noqa: PERF203
150
+ last_error = exc
151
+ if attempt >= self.max_retries:
152
+ break
153
+ time.sleep(self.backoff_base_s * (2**attempt))
154
+ # Wrap-and-rethrow ensures the adapter sees a single AssistantFailedError
155
+ # subclass regardless of which underlying exception triggered the failure.
156
+ raise WebhookFailedError(str(last_error)) from last_error
157
+
158
+
159
+ class LocalScriptAssistant:
160
+ """Subprocess assistant backend.
161
+
162
+ Spawns ``[script_path, *script_args]`` per turn and exchanges JSON over
163
+ stdin/stdout. The script must:
164
+
165
+ 1. Read a single JSON object from stdin matching ``_build_payload``'s
166
+ shape (``{"messages": [...], "playbooks": [...]}``).
167
+ 2. Print a single JSON object to stdout containing at least
168
+ ``{"content": "<assistant reply>"}``.
169
+ 3. Exit with code 0 on success. Any non-zero exit, malformed JSON,
170
+ missing/non-string ``content``, or timeout is treated as a failure
171
+ and counted against ``max_retries``.
172
+
173
+ The command is built as a list and passed to ``subprocess.run`` *without*
174
+ ``shell=True``, so config values cannot inject shell metacharacters.
175
+ Retry/timeout/backoff semantics mirror ``WebhookAssistant``.
176
+ """
177
+
178
+ def __init__(
179
+ self,
180
+ script_path: str,
181
+ script_args: list[str],
182
+ timeout_s: int,
183
+ max_retries: int,
184
+ backoff_base_s: float,
185
+ ) -> None:
186
+ self.command = [script_path, *script_args]
187
+ self.timeout_s = timeout_s
188
+ self.max_retries = max_retries
189
+ self.backoff_base_s = backoff_base_s
190
+
191
+ def __call__(
192
+ self, messages: list[ChatMessage], playbooks: list[AgentPlaybook]
193
+ ) -> str:
194
+ payload = _build_payload(messages, playbooks)
195
+ stdin = json.dumps(payload, ensure_ascii=False)
196
+ last_error: Exception | None = None
197
+ for attempt in range(self.max_retries + 1):
198
+ try:
199
+ # shell=False (the default) is intentional — see class docstring.
200
+ result = subprocess.run( # noqa: S603
201
+ self.command,
202
+ input=stdin,
203
+ text=True,
204
+ capture_output=True,
205
+ timeout=self.timeout_s,
206
+ check=False,
207
+ )
208
+ if result.returncode != 0:
209
+ # Truncate stderr to keep error messages bounded — long
210
+ # tracebacks would otherwise blow up DB rows and logs.
211
+ raise LocalScriptFailedError(
212
+ "assistant script exited with code "
213
+ f"{result.returncode}: {_truncate(result.stderr)}"
214
+ )
215
+ try:
216
+ data = json.loads(result.stdout)
217
+ except json.JSONDecodeError as exc:
218
+ raise LocalScriptFailedError(
219
+ f"assistant script returned invalid JSON: {_truncate(result.stdout)}"
220
+ ) from exc
221
+ content = data.get("content") if isinstance(data, dict) else None
222
+ if not isinstance(content, str):
223
+ raise LocalScriptFailedError("assistant script returned no content")
224
+ return content
225
+ except subprocess.TimeoutExpired:
226
+ # Timeouts come up via a different exception class than the
227
+ # validation errors above, but feed into the same retry budget.
228
+ last_error = LocalScriptFailedError(
229
+ f"assistant script timed out after {self.timeout_s}s"
230
+ )
231
+ if attempt >= self.max_retries:
232
+ break
233
+ time.sleep(self.backoff_base_s * (2**attempt))
234
+ except Exception as exc: # noqa: PERF203
235
+ last_error = exc
236
+ if attempt >= self.max_retries:
237
+ break
238
+ time.sleep(self.backoff_base_s * (2**attempt))
239
+ raise LocalScriptFailedError(str(last_error)) from last_error
240
+
241
+
242
+ def _truncate(value: str, limit: int = 1000) -> str:
243
+ """Cap a string for inclusion in error messages and stored rows."""
244
+ if len(value) <= limit:
245
+ return value
246
+ return f"{value[:limit]}..."