claude-smart 0.2.45 → 0.2.46

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 (322) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +34 -5
  3. package/bin/claude-smart.js +295 -5
  4. package/package.json +22 -3
  5. package/plugin/.claude-plugin/plugin.json +4 -2
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +22 -2
  8. package/plugin/commands/clear-all.md +1 -0
  9. package/plugin/commands/dashboard.md +1 -0
  10. package/plugin/commands/learn.md +1 -0
  11. package/plugin/commands/restart.md +1 -0
  12. package/plugin/commands/show.md +1 -0
  13. package/plugin/dashboard/app/configure/env/page.tsx +40 -14
  14. package/plugin/dashboard/app/configure/server/page.tsx +51 -1
  15. package/plugin/dashboard/app/preferences/[id]/page.tsx +8 -8
  16. package/plugin/dashboard/app/skills/project/[id]/page.tsx +7 -3
  17. package/plugin/dashboard/app/skills/shared/[id]/page.tsx +10 -3
  18. package/plugin/dashboard/lib/claude-settings-file.ts +20 -10
  19. package/plugin/dashboard/lib/reflexio-client.ts +16 -0
  20. package/plugin/dashboard/lib/status.ts +10 -3
  21. package/plugin/dashboard/lib/types.ts +18 -6
  22. package/plugin/hooks/codex-hooks.json +0 -1
  23. package/plugin/opencode/assistant-buffer.ts +108 -0
  24. package/plugin/opencode/dist/assistant-buffer.js +96 -0
  25. package/plugin/opencode/dist/internal.js +12 -0
  26. package/plugin/opencode/dist/payload.js +85 -0
  27. package/plugin/opencode/dist/server.mjs +158 -0
  28. package/plugin/opencode/internal.ts +18 -0
  29. package/plugin/opencode/package.json +3 -0
  30. package/plugin/opencode/payload.ts +90 -0
  31. package/plugin/opencode/server.mts +174 -0
  32. package/plugin/opencode/tsconfig.json +13 -0
  33. package/plugin/pyproject.toml +20 -3
  34. package/plugin/scripts/_lib.sh +5 -1
  35. package/plugin/scripts/backend-service.sh +22 -2
  36. package/plugin/scripts/ensure-plugin-root.sh +4 -4
  37. package/plugin/scripts/hook_entry.sh +1 -1
  38. package/plugin/scripts/opencode-claude-compat +4 -0
  39. package/plugin/scripts/opencode-claude-compat.cmd +3 -0
  40. package/plugin/scripts/opencode-claude-compat.js +225 -0
  41. package/plugin/scripts/smart-install.sh +10 -8
  42. package/plugin/src/README.md +1 -1
  43. package/plugin/src/claude_smart/cli.py +304 -6
  44. package/plugin/src/claude_smart/env_config.py +12 -4
  45. package/plugin/src/claude_smart/events/session_start.py +26 -7
  46. package/plugin/src/claude_smart/events/stop.py +1 -1
  47. package/plugin/src/claude_smart/ids.py +1 -1
  48. package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
  49. package/plugin/src/claude_smart/runtime.py +7 -1
  50. package/plugin/uv.lock +1 -1
  51. package/plugin/vendor/reflexio/.env.example +54 -30
  52. package/plugin/vendor/reflexio/README.md +14 -8
  53. package/plugin/vendor/reflexio/pyproject.toml +13 -1
  54. package/plugin/vendor/reflexio/reflexio/README.md +1 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
  56. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
  57. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
  63. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
  64. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
  65. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
  66. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
  67. package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
  68. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
  69. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
  70. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
  71. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
  72. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
  141. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
  142. package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
  143. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
  144. package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
  145. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
  146. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
  147. package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
  148. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
  149. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
  150. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
  151. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
  152. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
  153. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
  154. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
  155. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
  156. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
  157. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
  158. package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
  159. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
  160. package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
  161. package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
  162. package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
  163. package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
  164. package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
  165. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
  166. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
  167. package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
  168. package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
  169. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
  170. package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
  171. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
  172. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
  173. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
  174. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
  175. package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
  176. package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
  177. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
  178. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
  179. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
  180. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
  181. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
  182. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
  183. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
  184. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
  185. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
  186. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
  187. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
  188. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
  189. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
  190. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
  191. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
  192. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
  193. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
  194. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
  195. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
  196. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
  197. package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
  198. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
  199. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
  200. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
  201. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
  202. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
  203. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
  204. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
  205. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
  206. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
  207. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
  208. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
  209. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
  210. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
  211. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
  212. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
  213. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
  214. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
  215. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
  216. package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
  217. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
  218. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
  219. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
  220. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
  221. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
  222. package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
  223. package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
  224. package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
  225. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
  226. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
  227. package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
  228. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
  229. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
  230. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
  231. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
  232. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
  233. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
  234. package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
  235. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
  236. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
  237. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
  238. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
  239. package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
  240. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
  241. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
  242. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
  243. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
  244. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
  245. package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
  246. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
  247. package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
  248. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
  249. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
  250. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
  251. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
  252. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
  253. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
  254. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
  255. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
  256. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
  257. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
  258. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
  259. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
  260. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
  261. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
  262. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
  263. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
  264. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
  265. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
  266. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
  267. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
  268. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
  269. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
  270. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
  271. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
  272. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
  273. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
  274. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
  275. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
  277. package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
  278. package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
  279. package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
  281. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
  282. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
  283. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
  284. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
  285. package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
  286. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
  287. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
  288. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
  289. package/scripts/setup-claude-smart.sh +8 -3
  290. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
  291. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
  292. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
  293. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
  294. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
  295. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
  296. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
  297. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
  298. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
  299. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
  300. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
  301. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
  302. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
  303. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
  304. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
  305. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
  306. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
  307. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
  308. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
  309. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
  310. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
  311. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
  312. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
  313. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
  317. /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
  318. /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
  319. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
  320. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
  321. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
  322. /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
@@ -40,15 +40,8 @@ if TYPE_CHECKING:
40
40
 
41
41
  logger = logging.getLogger(__name__)
42
42
 
43
- FINISH_EXTRACTION_TOOL_NAME = "finish_extraction"
44
43
  PROFILE_EXTRACTOR_KIND = "profile"
45
44
 
46
- # Max in-process retries when the model returns a plain-text turn with no tool
47
- # call (finished_reason="no_tool_call"). tool_choice="required" is not always
48
- # honored by every provider/model, so a single bad turn would otherwise drop the
49
- # extraction entirely. Retries re-issue the same prompt from scratch.
50
- _NO_TOOL_CALL_MAX_RETRIES = 2
51
-
52
45
 
53
46
  def _record_agent_usage_event(
54
47
  *,
@@ -85,17 +78,6 @@ class AgentRunResult:
85
78
  finished_reason: str
86
79
 
87
80
 
88
- @dataclass(slots=True)
89
- class _FinishExtractionContext:
90
- output: BaseModel | None = None
91
-
92
-
93
- @dataclass(slots=True)
94
- class _ExtractionAgentToolContext:
95
- finish_context: _FinishExtractionContext
96
- extra_tool_context: Any | None = None
97
-
98
-
99
81
  def _format_resolved_tool_result(record: PendingToolCallRecord) -> str:
100
82
  resolved_at = record.resolved_at.isoformat() if record.resolved_at else "unknown"
101
83
  return (
@@ -106,7 +88,7 @@ def _format_resolved_tool_result(record: PendingToolCallRecord) -> str:
106
88
  f"Result: {record.result or {}}\n\n"
107
89
  "Use this Agent Builder feedback only if it is relevant to the "
108
90
  "current extraction window. If it adds or corrects durable profile or "
109
- "playbook information, include that in finish_extraction."
91
+ "playbook information, include that in your structured extraction result."
110
92
  )
111
93
 
112
94
 
@@ -128,22 +110,6 @@ def append_resolved_tool_result_context(
128
110
  ]
129
111
 
130
112
 
131
- def _finish_handler(args: BaseModel, ctx: Any) -> dict[str, Any]:
132
- ctx = getattr(ctx, "finish_context", ctx)
133
- if not isinstance(ctx, _FinishExtractionContext):
134
- raise TypeError(f"Expected _FinishExtractionContext, got {type(ctx).__name__}")
135
- ctx.output = args
136
- return {"status": "completed"}
137
-
138
-
139
- def create_finish_extraction_tool(output_schema: type[BaseModel]) -> Tool:
140
- return Tool(
141
- name=FINISH_EXTRACTION_TOOL_NAME,
142
- args_model=output_schema,
143
- handler=_finish_handler,
144
- )
145
-
146
-
147
113
  def _pending_tool_call_config(request_context: RequestContext) -> Any | None:
148
114
  root_config = request_context.configurator.get_config()
149
115
  return (
@@ -361,90 +327,38 @@ class ResumableExtractionAgent:
361
327
  if run.max_steps_remaining is not None:
362
328
  max_steps = min(max_steps, max(0, run.max_steps_remaining))
363
329
 
364
- # When only finish_extraction is registered (no human/prior-knowledge
365
- # tools), force that tool so the degenerate one-call loop is strictly
366
- # equivalent to the old single-shot response_format extraction —
367
- # the model cannot return a no-tool turn and yield empty output.
330
+ # The extractor delivers its result as a native structured response
331
+ # (response_format=output_schema): a turn with no tool call IS the
332
+ # committed output, parsed into output_schema. ask_human /
333
+ # attach_pending_info_request stay real tools the model may call
334
+ # mid-run, so tool_choice="auto" — forcing a tool would suppress the
335
+ # structured finish and is what produced the no_tool_call failures.
368
336
  #
369
- # When the async-info tools are also registered we cannot force a single
370
- # tool (the model must be free to pick ask_human vs finish_extraction),
371
- # but we still require *some* tool call via "required". This prevents a
372
- # weak tool-caller (e.g. MiniMax) from emitting the answer as plain text
373
- # with zero tool_calls, which the loop would otherwise treat as a no-op
374
- # finish and drop the output.
375
- tool_choice: str | dict[str, Any] = (
376
- {
377
- "type": "function",
378
- "function": {"name": FINISH_EXTRACTION_TOOL_NAME},
379
- }
380
- if not extra_tools
381
- else "required"
337
+ # No retry loop: a plain (no-tool) turn is now the SUCCESS terminus
338
+ # (finished_reason="structured_output"), not a dropped output, and the
339
+ # client already retries once on a malformed structured parse. The
340
+ # async-info tool handlers read ctx via getattr(ctx, "extra_tool_context",
341
+ # ctx), so the bare context object can be passed directly.
342
+ registry = ToolRegistry(list(extra_tools or []))
343
+ result = run_tool_loop(
344
+ client=self.client,
345
+ messages=messages,
346
+ registry=registry,
347
+ model_role=self.model_role,
348
+ max_steps=max_steps,
349
+ ctx=extra_tool_context,
350
+ response_format=output_schema,
351
+ tool_choice="auto",
352
+ log_label=log_label,
382
353
  )
383
354
 
384
- # Retry only the no_tool_call termination: the model emitted plain text
385
- # with zero tool calls, so nothing was committed and re-issuing the same
386
- # prompt is safe. Each attempt uses a fresh finish_ctx/registry so no
387
- # partial state leaks across attempts. We do NOT retry once the model has
388
- # already registered async tool calls (e.g. attach_pending_info_request)
389
- # — restarting from scratch would discard them.
390
- for attempt in range(_NO_TOOL_CALL_MAX_RETRIES + 1):
391
- finish_ctx = _FinishExtractionContext()
392
- ctx: Any = (
393
- _ExtractionAgentToolContext(
394
- finish_context=finish_ctx,
395
- extra_tool_context=extra_tool_context,
396
- )
397
- if extra_tool_context is not None
398
- else finish_ctx
399
- )
400
- registry = ToolRegistry(
401
- [*(extra_tools or []), create_finish_extraction_tool(output_schema)]
402
- )
403
-
404
- result = run_tool_loop(
405
- client=self.client,
406
- messages=messages,
407
- registry=registry,
408
- model_role=self.model_role,
409
- max_steps=max_steps,
410
- ctx=ctx,
411
- finish_tool_name=FINISH_EXTRACTION_TOOL_NAME,
412
- tool_choice=tool_choice,
413
- log_label=log_label,
414
- )
415
-
416
- should_retry = (
417
- result.finished_reason == "no_tool_call"
418
- and not result.pending_tool_call_ids
419
- and attempt < _NO_TOOL_CALL_MAX_RETRIES
420
- )
421
- if not should_retry:
422
- break
423
- logger.warning(
424
- "event=extraction_agent_retry org_id=%s user_id=%s "
425
- "extractor_kind=%s run_id=%s request_id=%s "
426
- "finished_reason=%s attempt=%d max_retries=%d",
427
- run.binding.org_id,
428
- run.binding.user_id,
429
- run.binding.extractor_kind,
430
- run.id,
431
- run.binding.request_id,
432
- result.finished_reason,
433
- attempt + 1,
434
- _NO_TOOL_CALL_MAX_RETRIES,
435
- )
436
- _record_agent_usage_event(
437
- run=run,
438
- event_name="extraction_agent_retry",
439
- error_kind=result.finished_reason,
440
- metadata={"attempt": attempt + 1},
441
- )
442
-
443
- committed_output = (
444
- finish_ctx.output.model_dump() if finish_ctx.output is not None else None
445
- )
355
+ output = result.structured_output
356
+ committed_output = output.model_dump() if output is not None else None
446
357
  active_statuses = (AgentRunStatus.RUNNING, AgentRunStatus.RESUMING)
447
- if result.finished_reason == "finish_tool" and committed_output is not None:
358
+ if (
359
+ result.finished_reason == "structured_output"
360
+ and committed_output is not None
361
+ ):
448
362
  stored_run = self.storage.update_agent_run_status(
449
363
  run.id,
450
364
  AgentRunStatus.AGENT_COMPLETED,
@@ -515,19 +429,19 @@ class ResumableExtractionAgent:
515
429
  run.id,
516
430
  run.binding.request_id,
517
431
  result.finished_reason,
518
- finish_ctx.output is not None,
432
+ output is not None,
519
433
  )
520
434
  _record_agent_usage_event(
521
435
  run=run,
522
436
  event_name="extraction_agent_failed",
523
437
  outcome="failed",
524
438
  error_kind=result.finished_reason,
525
- metadata={"has_output": finish_ctx.output is not None},
439
+ metadata={"has_output": output is not None},
526
440
  )
527
441
 
528
442
  return AgentRunResult(
529
443
  run_id=run.id,
530
- output=finish_ctx.output,
444
+ output=output,
531
445
  pending_tool_call_ids=result.pending_tool_call_ids,
532
446
  messages=result.messages,
533
447
  trace=result.trace,
@@ -28,29 +28,29 @@ from reflexio.server.services.extraction.resumable_agent import (
28
28
  ResumableExtractionAgent,
29
29
  create_pending_info_tools_for_extractor_kind,
30
30
  )
31
- from reflexio.server.services.playbook.playbook_extractor import PlaybookExtractor
32
- from reflexio.server.services.playbook.playbook_generation_service import (
33
- PlaybookGenerationService,
34
- PlaybookGenerationServiceConfig,
35
- )
31
+ from reflexio.server.services.playbook.components.extractor import PlaybookExtractor
36
32
  from reflexio.server.services.playbook.playbook_service_utils import (
37
33
  StructuredPlaybookList,
38
34
  construct_expert_playbook_extraction_messages,
39
35
  construct_playbook_extraction_messages_from_sessions,
40
36
  has_expert_content,
41
37
  )
42
- from reflexio.server.services.profile.profile_extractor import (
38
+ from reflexio.server.services.playbook.service import (
39
+ PlaybookGenerationService,
40
+ PlaybookGenerationServiceConfig,
41
+ )
42
+ from reflexio.server.services.profile.components.extractor import (
43
43
  MAX_EXISTING_PROFILES_FOR_CONTEXT,
44
44
  ProfileExtractor,
45
45
  )
46
- from reflexio.server.services.profile.profile_generation_service import (
47
- ProfileGenerationService,
48
- ProfileGenerationServiceConfig,
49
- )
50
46
  from reflexio.server.services.profile.profile_generation_service_utils import (
51
47
  StructuredProfilesOutput,
52
48
  construct_profile_extraction_messages_from_sessions,
53
49
  )
50
+ from reflexio.server.services.profile.service import (
51
+ ProfileGenerationService,
52
+ ProfileGenerationServiceConfig,
53
+ )
54
54
  from reflexio.server.services.service_utils import (
55
55
  extract_interactions_from_request_interaction_data_models,
56
56
  )
@@ -61,6 +61,7 @@ from reflexio.server.services.storage.storage_base import (
61
61
  PendingToolCallRecord,
62
62
  PendingToolCallStatus,
63
63
  )
64
+ from reflexio.server.services.tagging.tagging_scheduler import schedule_tagging
64
65
  from reflexio.server.site_var.site_var_manager import SiteVarManager
65
66
  from reflexio.server.tracing import sentry_tags
66
67
 
@@ -133,7 +134,7 @@ def _request_interaction_models_from_ids(
133
134
  )
134
135
  models.append(
135
136
  RequestInteractionDataModel(
136
- session_id=request.session_id or request.request_id,
137
+ session_id=request.session_id,
137
138
  request=request,
138
139
  interactions=ordered,
139
140
  )
@@ -272,6 +273,7 @@ class ExtractionResumeWorker:
272
273
  try:
273
274
  self.storage.update_agent_run_status(run.id, AgentRunStatus.FINALIZING)
274
275
  self._finalize_items(run, items)
276
+ self._schedule_finalized_tagging(run)
275
277
  self.storage.consume_run_tool_dependencies(run.id)
276
278
  finalized_status = (
277
279
  AgentRunStatus.FINALIZED_PENDING_TOOL
@@ -315,6 +317,7 @@ class ExtractionResumeWorker:
315
317
  try:
316
318
  items, pending_tool_call_ids = self._items_from_committed_output(run)
317
319
  self._finalize_items(run, items)
320
+ self._schedule_finalized_tagging(run)
318
321
  self.storage.consume_run_tool_dependencies(run.id)
319
322
  finalized_status = (
320
323
  AgentRunStatus.FINALIZED_PENDING_TOOL
@@ -460,11 +463,6 @@ class ExtractionResumeWorker:
460
463
  else ""
461
464
  ),
462
465
  extraction_definition_prompt=extractor_config.extraction_definition_prompt.strip(),
463
- metadata_definition_prompt=(
464
- extractor_config.metadata_definition_prompt.strip()
465
- if extractor_config.metadata_definition_prompt
466
- else None
467
- ),
468
466
  existing_profiles=context_profiles,
469
467
  )
470
468
  result = self._resume_agent(
@@ -777,3 +775,28 @@ class ExtractionResumeWorker:
777
775
  raise ResumeWorkerError(
778
776
  f"Unsupported extractor kind {run.binding.extractor_kind!r}"
779
777
  )
778
+
779
+ def _schedule_finalized_tagging(self, run: AgentRunRecord) -> None:
780
+ user_id = run.binding.user_id
781
+ if not user_id:
782
+ return
783
+ if run.binding.extractor_kind not in ("profile", "playbook"):
784
+ return
785
+
786
+ # Defer tagging off this worker's drain loop. The pass is idempotent
787
+ # (skips already-tagged entities), so running both profile and playbook
788
+ # tagging is safe regardless of this run's extractor kind.
789
+ try:
790
+ schedule_tagging(
791
+ org_id=self.request_context.org_id,
792
+ user_id=user_id,
793
+ agent_version=run.binding.agent_version or "",
794
+ request_context=self.request_context,
795
+ llm_client=self.client,
796
+ )
797
+ except Exception:
798
+ logger.exception(
799
+ "Failed to schedule tagging for finalized %s run %s",
800
+ run.binding.extractor_kind,
801
+ run.id,
802
+ )
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import contextvars
4
+ import hashlib
4
5
  import logging
5
6
  import os
6
7
  import threading
@@ -21,33 +22,34 @@ from reflexio.models.api_schema.service_schemas import (
21
22
  from reflexio.models.config_schema import Config
22
23
  from reflexio.server.api_endpoints.request_context import RequestContext
23
24
  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 (
25
+ from reflexio.server.services.agent_success_evaluation.runner import (
28
26
  run_group_evaluation,
29
27
  )
30
- from reflexio.server.services.operation_state_utils import OperationStateManager
31
- from reflexio.server.services.playbook.playbook_generation_service import (
32
- PlaybookGenerationService,
28
+ from reflexio.server.services.agent_success_evaluation.scheduler import (
29
+ GroupEvaluationScheduler,
33
30
  )
31
+ from reflexio.server.services.operation_state_utils import OperationStateManager
34
32
  from reflexio.server.services.playbook.playbook_service_utils import (
35
33
  PlaybookGenerationRequest,
36
34
  )
37
- from reflexio.server.services.profile.profile_generation_service import (
38
- ProfileGenerationService,
35
+ from reflexio.server.services.playbook.service import (
36
+ PlaybookGenerationService,
39
37
  )
40
38
  from reflexio.server.services.profile.profile_generation_service_utils import (
41
39
  ProfileGenerationRequest,
42
40
  )
43
- from reflexio.server.services.reflection.reflection_service import ReflectionService
41
+ from reflexio.server.services.profile.service import (
42
+ ProfileGenerationService,
43
+ )
44
44
  from reflexio.server.services.reflection.reflection_service_utils import (
45
45
  ReflectionServiceRequest,
46
46
  )
47
+ from reflexio.server.services.reflection.service import ReflectionService
47
48
  from reflexio.server.services.storage.retention import (
48
49
  delete_count_for_retention,
49
50
  get_row_retention_limits,
50
51
  )
52
+ from reflexio.server.services.tagging.tagging_scheduler import schedule_tagging
51
53
  from reflexio.server.tracing import sentry_tags
52
54
  from reflexio.server.usage_metrics import record_usage_event
53
55
 
@@ -79,6 +81,15 @@ _retention_cleanup_last_run: dict[tuple[str, str], float] = {}
79
81
  _retention_cleanup_lock = threading.Lock()
80
82
 
81
83
 
84
+ def _stable_group_sampling_fraction(
85
+ org_id: str, user_id: str, session_id: str
86
+ ) -> float:
87
+ """Return a deterministic [0, 1) sample value for one session."""
88
+ key = f"{org_id}\0{user_id}\0{session_id}".encode()
89
+ digest = hashlib.sha256(key).digest()
90
+ return int.from_bytes(digest[:8], "big") / 2**64
91
+
92
+
82
93
  @dataclass
83
94
  class GenerationServiceResult:
84
95
  """Result of a GenerationService.run call.
@@ -204,7 +215,7 @@ class GenerationService:
204
215
  org_id=self.org_id,
205
216
  user_id=user_id,
206
217
  request_id=request_id,
207
- session_id=publish_user_interaction_request.session_id or None,
218
+ session_id=publish_user_interaction_request.session_id,
208
219
  source=publish_user_interaction_request.source,
209
220
  agent_version=agent_version,
210
221
  event_name="publish_request_received",
@@ -213,16 +224,15 @@ class GenerationService:
213
224
  count_value=len(new_interactions),
214
225
  )
215
226
 
216
- # Store Request propagate customer-stamped metadata so the
217
- # eval pipeline (e.g. F2 sticky-group aggregator) can read it
218
- # back from the first request of each session.
227
+ # Store Request before adding interactions so downstream workers can
228
+ # resolve the session's source and evaluation-only status.
219
229
  new_request = Request(
220
230
  request_id=request_id,
221
231
  user_id=user_id,
222
232
  source=publish_user_interaction_request.source,
223
233
  agent_version=agent_version,
224
- session_id=publish_user_interaction_request.session_id or None,
225
- metadata=publish_user_interaction_request.metadata,
234
+ session_id=publish_user_interaction_request.session_id,
235
+ evaluation_only=publish_user_interaction_request.evaluation_only,
226
236
  )
227
237
  self.storage.add_request(new_request) # type: ignore[reportOptionalMemberAccess]
228
238
 
@@ -234,6 +244,33 @@ class GenerationService:
234
244
  # Extract source (empty string treated as None)
235
245
  source = publish_user_interaction_request.source or None
236
246
 
247
+ if publish_user_interaction_request.evaluation_only:
248
+ self._schedule_group_evaluation_if_needed(
249
+ new_request=new_request,
250
+ user_id=user_id,
251
+ agent_version=agent_version,
252
+ source=source,
253
+ )
254
+ record_usage_event(
255
+ org_id=self.org_id,
256
+ user_id=user_id,
257
+ request_id=request_id,
258
+ session_id=new_request.session_id,
259
+ source=source,
260
+ agent_version=agent_version,
261
+ backend="evaluation_only",
262
+ event_name="publish_request_succeeded",
263
+ event_category="publish",
264
+ outcome="success",
265
+ count_value=len(new_interactions),
266
+ duration_ms=int((time.perf_counter() - publish_start) * 1000),
267
+ metadata={
268
+ "evaluation_only": True,
269
+ "warning_count": len(result.warnings),
270
+ },
271
+ )
272
+ return result
273
+
237
274
  if (
238
275
  not publish_user_interaction_request.override_learning_stall
239
276
  and (stall_warning := self._active_learning_stall_warning()) is not None
@@ -262,7 +299,10 @@ class GenerationService:
262
299
  # profile/playbook context. Wrapped in a broad except so a
263
300
  # reflection bug never breaks the publish.
264
301
  self._maybe_run_reflection(
265
- user_id=user_id, agent_version=agent_version, source=source
302
+ user_id=user_id,
303
+ request_id=request_id,
304
+ agent_version=agent_version,
305
+ source=source,
266
306
  )
267
307
 
268
308
  # Create generation services and requests
@@ -343,7 +383,24 @@ class GenerationService:
343
383
  finally:
344
384
  executor.shutdown(wait=False, cancel_futures=True)
345
385
 
346
- # Schedule delayed group evaluation if session_id is present
386
+ # Tagging runs an LLM call per newly generated entity, so defer it off
387
+ # the publish path. The scheduler debounces bursts and is idempotent
388
+ # (already-tagged entities are skipped).
389
+ try:
390
+ schedule_tagging(
391
+ org_id=self.org_id,
392
+ user_id=user_id,
393
+ agent_version=agent_version,
394
+ request_context=self.request_context,
395
+ llm_client=self.client,
396
+ )
397
+ except Exception:
398
+ logger.exception(
399
+ "Failed to schedule tagging for publish request %s",
400
+ request_id,
401
+ )
402
+
403
+ # Schedule delayed group evaluation for the required session.
347
404
  self._schedule_group_evaluation_if_needed(
348
405
  new_request=new_request,
349
406
  user_id=user_id,
@@ -373,7 +430,7 @@ class GenerationService:
373
430
  org_id=self.org_id,
374
431
  user_id=user_id,
375
432
  request_id=result.request_id,
376
- session_id=publish_user_interaction_request.session_id or None,
433
+ session_id=publish_user_interaction_request.session_id,
377
434
  source=publish_user_interaction_request.source,
378
435
  agent_version=agent_version,
379
436
  event_name="publish_request_failed",
@@ -408,7 +465,7 @@ class GenerationService:
408
465
  agent_version: str,
409
466
  source: str | None,
410
467
  ) -> None:
411
- """Enqueue agent-success evaluation for this session, if session_id is set.
468
+ """Enqueue agent-success evaluation for this session.
412
469
 
413
470
  Must be called once per publish — from BOTH the classic and the agentic
414
471
  extraction code paths — so that ``AgentSuccessEvaluationResult`` records
@@ -417,13 +474,20 @@ class GenerationService:
417
474
 
418
475
  Args:
419
476
  new_request (Request): The just-stored request whose session is being
420
- published into. ``new_request.session_id`` gates scheduling.
477
+ published into.
421
478
  user_id (str): The user owning the session.
422
479
  agent_version (str): Agent version string carried into the evaluator.
423
480
  source (str | None): Optional source label.
424
481
  """
425
482
  session_id = new_request.session_id
426
- if not session_id:
483
+ if not self._should_sample_group_evaluation(
484
+ user_id=user_id, session_id=session_id
485
+ ):
486
+ logger.info(
487
+ "Skipping group evaluation scheduling for unsampled session=%s user=%s",
488
+ session_id,
489
+ user_id,
490
+ )
427
491
  return
428
492
 
429
493
  scheduler = GroupEvaluationScheduler.get_instance()
@@ -464,8 +528,25 @@ class GenerationService:
464
528
  ),
465
529
  )
466
530
 
531
+ def _should_sample_group_evaluation(self, *, user_id: str, session_id: str) -> bool:
532
+ config = self.configurator.get_config()
533
+ agent_success_config = getattr(config, "agent_success_config", None)
534
+ if agent_success_config is None:
535
+ return False
536
+
537
+ sampling_rate = agent_success_config.sampling_rate
538
+ if sampling_rate >= 1.0:
539
+ return True
540
+ if sampling_rate <= 0.0:
541
+ return False
542
+
543
+ return (
544
+ _stable_group_sampling_fraction(self.org_id, user_id, session_id)
545
+ < sampling_rate
546
+ )
547
+
467
548
  def _maybe_run_reflection(
468
- self, *, user_id: str, agent_version: str, source: str | None
549
+ self, *, user_id: str, request_id: str, agent_version: str, source: str | None
469
550
  ) -> None:
470
551
  """Best-effort reflection pass before extraction.
471
552
 
@@ -480,6 +561,7 @@ class GenerationService:
480
561
  service.run(
481
562
  ReflectionServiceRequest(
482
563
  user_id=user_id,
564
+ request_id=request_id,
483
565
  agent_version=agent_version,
484
566
  source=source,
485
567
  )