claude-smart 0.2.44 → 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 (323) 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 +77 -29
  35. package/plugin/scripts/backend-service.sh +27 -5
  36. package/plugin/scripts/dashboard-service.sh +7 -5
  37. package/plugin/scripts/ensure-plugin-root.sh +4 -4
  38. package/plugin/scripts/hook_entry.sh +3 -3
  39. package/plugin/scripts/opencode-claude-compat +4 -0
  40. package/plugin/scripts/opencode-claude-compat.cmd +3 -0
  41. package/plugin/scripts/opencode-claude-compat.js +225 -0
  42. package/plugin/scripts/smart-install.sh +10 -8
  43. package/plugin/src/README.md +1 -1
  44. package/plugin/src/claude_smart/cli.py +304 -6
  45. package/plugin/src/claude_smart/env_config.py +12 -4
  46. package/plugin/src/claude_smart/events/session_start.py +26 -7
  47. package/plugin/src/claude_smart/events/stop.py +1 -1
  48. package/plugin/src/claude_smart/ids.py +1 -1
  49. package/plugin/src/claude_smart/reflexio_adapter.py +5 -5
  50. package/plugin/src/claude_smart/runtime.py +7 -1
  51. package/plugin/uv.lock +1 -1
  52. package/plugin/vendor/reflexio/.env.example +54 -30
  53. package/plugin/vendor/reflexio/README.md +14 -8
  54. package/plugin/vendor/reflexio/pyproject.toml +13 -1
  55. package/plugin/vendor/reflexio/reflexio/README.md +1 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/README.md +9 -7
  57. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +10 -1
  58. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +22 -5
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +34 -4
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +12 -7
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +13 -6
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +210 -50
  63. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +15 -2
  64. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +292 -22
  65. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +29 -4
  66. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +17 -8
  67. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +13 -10
  68. package/plugin/vendor/reflexio/reflexio/client/client.py +57 -13
  69. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +135 -257
  70. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/bin/openclaw-smart.js +13 -0
  71. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/npm/openclaw-smart/package.json +15 -0
  72. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/README.md +38 -0
  73. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +151 -110
  74. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +20 -10
  75. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +28 -6
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/pyproject.toml +42 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/_lib.sh +371 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-log-runner.sh +33 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/backend-service.sh +271 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/cli.sh +68 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/dashboard-open.sh +15 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/ensure-plugin-root.sh +84 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/hook_entry.sh +106 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/npm-cli.js +219 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/scripts/smart-install.sh +269 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/clear-all/SKILL.md +8 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/dashboard/SKILL.md +8 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/learn/SKILL.md +10 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +15 -44
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/restart/SKILL.md +6 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/show/SKILL.md +8 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/cli.py +634 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_format.py +224 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/context_inject.py +79 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/__init__.py +0 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/after_tool_call.py +160 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/agent_end.py +187 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_prompt_build.py +69 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/before_tool_call.py +30 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_end.py +36 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/events/session_start.py +130 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/hook.py +131 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/ids.py +94 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/internal_call.py +75 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/oc_cite.py +196 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/optimizer_assistant.py +272 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/publish.py +96 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/query_compose.py +66 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/reflexio_adapter.py +336 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/runtime.py +47 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/stall_banner.py +61 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +323 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/__init__.py +0 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/__init__.py +0 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_e2e_session_loop.py +190 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_publish_to_local_reflexio_integration.py +112 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_recursion_guard_integration.py +86 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/integration/test_search_inject_integration.py +144 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_cli.py +184 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_after_tool_call.py +142 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_agent_end.py +233 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_prompt_build.py +116 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_before_tool_call.py +35 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_end.py +47 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_events_session_start.py +109 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_hook_dispatch.py +117 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_ids.py +41 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_internal_call.py +50 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_oc_cite.py +88 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_publish.py +48 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_query_compose.py +48 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_reflexio_adapter.py +188 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_runtime.py +41 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +235 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/__mocks__/plugin-entry-stub.ts +6 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_npm_cli.test.ts +56 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests-ts/test_shim_dispatch.test.ts +171 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tsconfig.build.json +18 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{tsconfig.json → plugin/tsconfig.json} +2 -2
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/uv.lock +3835 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/vitest.config.ts +18 -0
  142. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +238 -10
  143. package/plugin/vendor/reflexio/reflexio/lib/_config.py +11 -4
  144. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +16 -5
  145. package/plugin/vendor/reflexio/reflexio/lib/_lineage_parity_readers.py +187 -0
  146. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +198 -6
  147. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +1 -1
  148. package/plugin/vendor/reflexio/reflexio/lib/_search.py +29 -20
  149. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +2 -1
  150. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +127 -38
  151. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +4 -0
  152. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +64 -41
  153. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +19 -0
  154. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +12 -5
  155. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +52 -0
  156. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +5 -1
  157. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +5 -1
  158. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +88 -7
  159. package/plugin/vendor/reflexio/reflexio/models/structured_output.py +148 -0
  160. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +3 -3
  161. package/plugin/vendor/reflexio/reflexio/server/README.md +45 -32
  162. package/plugin/vendor/reflexio/reflexio/server/__init__.py +29 -5
  163. package/plugin/vendor/reflexio/reflexio/server/__main__.py +2 -2
  164. package/plugin/vendor/reflexio/reflexio/server/_auth.py +65 -2
  165. package/plugin/vendor/reflexio/reflexio/server/api.py +734 -85
  166. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +7 -0
  167. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +3 -1
  168. package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +173 -0
  169. package/plugin/vendor/reflexio/reflexio/server/billing_signals.py +64 -0
  170. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +46 -16
  171. package/plugin/vendor/reflexio/reflexio/server/env_utils.py +65 -0
  172. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -4
  173. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +264 -77
  174. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +69 -7
  175. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +75 -16
  176. package/plugin/vendor/reflexio/reflexio/server/llm/providers/openclaw_provider.py +280 -0
  177. package/plugin/vendor/reflexio/reflexio/server/llm/token_accounting.py +48 -0
  178. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +107 -17
  179. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +360 -4
  180. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +1 -1
  181. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.7.0.prompt.md +85 -0
  182. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +1 -1
  183. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.3.0.prompt.md +253 -0
  184. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +1 -1
  185. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +74 -0
  186. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +1 -1
  187. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.3.0.prompt.md +266 -0
  188. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +266 -0
  189. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +1 -1
  190. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.4.0.prompt.md +137 -0
  191. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +1 -1
  192. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.3.0.prompt.md +34 -0
  193. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +5 -12
  194. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +5 -12
  195. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.2.0.prompt.md +155 -0
  196. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/tagging/v1.0.0.prompt.md +23 -0
  197. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +89 -32
  198. package/plugin/vendor/reflexio/reflexio/server/services/README.md +26 -11
  199. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +22 -0
  200. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/__init__.py +1 -0
  201. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +4 -2
  202. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +1 -0
  203. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/__init__.py +7 -0
  204. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluator.py → components/evaluator.py} +3 -16
  205. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +28 -72
  206. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{group_evaluation_runner.py → runner.py} +12 -10
  207. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{delayed_group_evaluator.py → scheduler.py} +10 -2
  208. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/{agent_success_evaluation_service.py → service.py} +36 -1
  209. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +160 -0
  210. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +5 -0
  211. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +1 -1
  212. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/README.md +9 -0
  213. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/__init__.py +0 -0
  214. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{rule_attribution.py → components/rule_attribution.py} +10 -9
  215. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +15 -24
  216. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +238 -164
  217. package/plugin/vendor/reflexio/reflexio/server/services/extraction/README.md +31 -0
  218. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +13 -3
  219. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +3 -2
  220. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +32 -118
  221. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +39 -16
  222. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +105 -23
  223. package/plugin/vendor/reflexio/reflexio/server/services/lineage/__init__.py +0 -0
  224. package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +193 -0
  225. package/plugin/vendor/reflexio/reflexio/server/services/lineage/resolve.py +98 -0
  226. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +26 -0
  227. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +11 -12
  228. package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/__init__.py +5 -0
  229. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_aggregator.py → components/aggregator.py} +316 -178
  230. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_consolidator.py → components/consolidator.py} +168 -62
  231. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_extractor.py → components/extractor.py} +5 -1
  232. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +74 -0
  233. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +33 -3
  234. package/plugin/vendor/reflexio/reflexio/server/services/playbook/{playbook_generation_service.py → service.py} +121 -19
  235. package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +84 -0
  236. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/README.md +10 -0
  237. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +2 -1
  238. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +178 -30
  239. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/README.md +9 -0
  240. package/plugin/vendor/reflexio/reflexio/server/services/profile/components/__init__.py +17 -0
  241. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_deduplicator.py → components/consolidator.py} +7 -6
  242. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_extractor.py → components/extractor.py} +30 -22
  243. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +6 -13
  244. package/plugin/vendor/reflexio/reflexio/server/services/profile/{profile_generation_service.py → service.py} +32 -50
  245. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +4 -8
  246. package/plugin/vendor/reflexio/reflexio/server/services/reflection/components/__init__.py +7 -0
  247. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +12 -1
  248. package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_service.py → service.py} +36 -16
  249. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +83 -6
  250. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +36 -1
  251. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/README.md +8 -0
  252. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +1 -2
  253. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +27 -0
  254. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +9 -9
  255. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
  256. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +4 -1
  257. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +642 -197
  258. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +61 -104
  259. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +628 -0
  260. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +38 -6
  261. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +978 -184
  262. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +519 -128
  263. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +77 -3
  264. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +23 -9
  265. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +5 -2
  266. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +131 -20
  267. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +2 -8
  268. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +5 -0
  269. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +36 -53
  270. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_lineage.py +215 -0
  271. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +20 -0
  272. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +243 -7
  273. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +121 -1
  274. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +60 -0
  275. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +51 -0
  276. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +17 -0
  277. package/plugin/vendor/reflexio/reflexio/server/services/tagging/README.md +8 -0
  278. package/plugin/vendor/reflexio/reflexio/server/services/tagging/__init__.py +1 -0
  279. package/plugin/vendor/reflexio/reflexio/server/services/tagging/service.py +200 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +149 -0
  281. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +229 -32
  282. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +2 -1
  283. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +120 -1
  284. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +4 -0
  285. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/search_settings.json +5 -0
  286. package/plugin/vendor/reflexio/reflexio/server/tracing.py +30 -0
  287. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +18 -0
  288. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -26
  289. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +41 -4
  290. package/scripts/setup-claude-smart.sh +8 -3
  291. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +0 -517
  292. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +0 -473
  293. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +0 -2156
  294. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +0 -18
  295. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +0 -241
  296. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +0 -140
  297. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +0 -113
  298. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +0 -52
  299. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +0 -103
  300. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +0 -156
  301. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +0 -134
  302. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +0 -24
  303. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +0 -278
  304. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +0 -164
  305. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +0 -36
  306. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +0 -35
  307. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +0 -27
  308. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +0 -31
  309. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +0 -42
  310. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +0 -49
  311. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +0 -91
  312. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +0 -50
  313. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +0 -13
  314. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +0 -192
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +0 -303
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +0 -138
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +0 -1125
  318. /package/plugin/vendor/reflexio/reflexio/integrations/{__init__.py → openclaw/plugin/src/openclaw_smart/__init__.py} +0 -0
  319. /package/plugin/vendor/reflexio/reflexio/integrations/openclaw/{types → plugin/types}/openclaw.d.ts +0 -0
  320. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{distribution.py → components/distribution.py} +0 -0
  321. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{hero_state.py → components/hero_state.py} +0 -0
  322. /package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/{shadow_aggregation.py → components/shadow_aggregation.py} +0 -0
  323. /package/plugin/vendor/reflexio/reflexio/server/services/reflection/{reflection_extractor.py → components/extractor.py} +0 -0
@@ -0,0 +1,336 @@
1
+ """Thin wrapper over ``reflexio.ReflexioClient`` for openclaw-smart's read/write paths.
2
+
3
+ Exists so hook handlers (a) don't import reflexio directly at module scope —
4
+ import failures shouldn't crash hooks — and (b) can be stubbed in tests.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import os
11
+ from collections.abc import Sequence
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ from dataclasses import dataclass
14
+ from typing import Any
15
+
16
+ from openclaw_smart import runtime
17
+
18
+ _LOGGER = logging.getLogger(__name__)
19
+
20
+ _ENV_URL = "REFLEXIO_URL"
21
+ _DEFAULT_URL = "http://localhost:8071/"
22
+ _SEARCH_MODE_HYBRID = "hybrid" # reflexio.models.config_schema.SearchMode.HYBRID
23
+ _UNIFIED_ENTITY_TYPES = ("profiles", "user_playbooks", "agent_playbooks")
24
+ _AGENT_PLAYBOOK_APPROVAL_STATUSES = ("pending", "approved")
25
+ _REJECTED_AGENT_PLAYBOOK_STATUS = "rejected"
26
+
27
+
28
+ @dataclass
29
+ class Adapter:
30
+ """Wraps the reflexio client and absorbs connection errors.
31
+
32
+ All methods degrade to a neutral no-op return (empty list / False) on
33
+ connection failure so a missing or down reflexio server never crashes
34
+ an openClaw hook.
35
+ """
36
+
37
+ url: str = ""
38
+
39
+ def __post_init__(self) -> None:
40
+ self.url = self.url or os.environ.get(_ENV_URL, _DEFAULT_URL)
41
+ self._client: Any | None = None
42
+
43
+ # -----------------------------------------------------------------
44
+ # Client lazy-initialization
45
+ # -----------------------------------------------------------------
46
+
47
+ def _get_client(self) -> Any | None:
48
+ """Return the ReflexioClient, or None if reflexio is unreachable/unimportable."""
49
+ if self._client is not None:
50
+ return self._client
51
+ try:
52
+ from reflexio import ReflexioClient # type: ignore[import-not-found]
53
+ except ImportError as exc:
54
+ _LOGGER.debug("reflexio not importable: %s", exc)
55
+ return None
56
+ try:
57
+ self._client = ReflexioClient(url_endpoint=self.url)
58
+ except Exception as exc: # noqa: BLE001 — adapter must never raise.
59
+ _LOGGER.warning("Failed to construct ReflexioClient: %s", exc)
60
+ return None
61
+ return self._client
62
+
63
+ # -----------------------------------------------------------------
64
+ # Writes
65
+ # -----------------------------------------------------------------
66
+
67
+ def publish(
68
+ self,
69
+ *,
70
+ session_id: str,
71
+ project_id: str,
72
+ interactions: Sequence[dict[str, Any]],
73
+ force_extraction: bool = False,
74
+ skip_aggregation: bool = False,
75
+ ) -> bool:
76
+ """Publish buffered interactions to reflexio. Returns True on success."""
77
+ if not interactions:
78
+ return True
79
+ client = self._get_client()
80
+ if client is None:
81
+ return False
82
+ try:
83
+ client.publish_interaction(
84
+ user_id=project_id,
85
+ interactions=list(interactions),
86
+ agent_version=runtime.agent_version(),
87
+ session_id=session_id,
88
+ wait_for_response=False,
89
+ force_extraction=force_extraction,
90
+ skip_aggregation=skip_aggregation,
91
+ )
92
+ return True
93
+ except Exception as exc: # noqa: BLE001
94
+ _LOGGER.warning("publish_interaction failed: %s", exc)
95
+ return False
96
+
97
+ def apply_extraction_defaults(self, *, window_size: int, stride_size: int) -> bool:
98
+ """Push openclaw-smart's preferred extraction defaults to the reflexio server.
99
+
100
+ Reads the current ``Config`` and only issues a ``set_config`` when the
101
+ server-side values differ, so steady state is a single cheap GET.
102
+
103
+ Reflexio persists ``Config`` to disk, so once these values land they
104
+ survive backend restarts. The flip side: if an operator customizes
105
+ ``window_size``/``stride_size`` via the dashboard, this call will
106
+ overwrite those values back to the openclaw-smart defaults on the
107
+ next session_start. To change the defaults, edit the constants at
108
+ the call site in ``events/session_start.py``.
109
+ """
110
+ client = self._get_client()
111
+ if client is None:
112
+ return False
113
+ try:
114
+ config = client.get_config()
115
+ if (
116
+ getattr(config, "window_size", None) == window_size
117
+ and getattr(config, "stride_size", None) == stride_size
118
+ ):
119
+ return True
120
+ config.window_size = window_size
121
+ config.stride_size = stride_size
122
+ client.set_config(config)
123
+ return True
124
+ except Exception as exc: # noqa: BLE001 — adapter must never raise.
125
+ _LOGGER.warning("apply_extraction_defaults failed: %s", exc)
126
+ return False
127
+
128
+ def apply_optimizer_defaults(
129
+ self, *, script_path: str, timeout_seconds: int = 300
130
+ ) -> bool:
131
+ """Push openclaw-smart's shared skill optimizer defaults to reflexio.
132
+
133
+ Idempotent compare-then-write: reads ``Config``, only issues a
134
+ ``set_config`` when the server-side values differ from the desired
135
+ dict below. Called unconditionally from session_start; the caller's
136
+ only escape hatch is ``OPENCLAW_SMART_ENABLE_OPTIMIZER=0``.
137
+ """
138
+ client = self._get_client()
139
+ if client is None:
140
+ return False
141
+ try:
142
+ config = client.get_config()
143
+ opt = getattr(config, "playbook_optimizer_config", None)
144
+ if opt is None:
145
+ return False
146
+
147
+ desired = {
148
+ "enabled": True,
149
+ "optimize_user_playbooks": False,
150
+ "optimize_agent_playbooks": True,
151
+ "auto_update_user_playbooks": True,
152
+ "min_commit_windows": 1,
153
+ "max_metric_calls": 15,
154
+ "assistant_script_path": script_path,
155
+ "assistant_script_args": [],
156
+ "webhook_url": None,
157
+ "webhook_timeout_seconds": timeout_seconds,
158
+ }
159
+ if all(getattr(opt, key, None) == value for key, value in desired.items()):
160
+ return True
161
+ for key, value in desired.items():
162
+ setattr(opt, key, value)
163
+ client.set_config(config)
164
+ return True
165
+ except Exception as exc: # noqa: BLE001 — adapter must never raise.
166
+ _LOGGER.warning("apply_optimizer_defaults failed: %s", exc)
167
+ return False
168
+
169
+ # -----------------------------------------------------------------
170
+ # Stall-state reads/writes (used by session_start banner)
171
+ # -----------------------------------------------------------------
172
+
173
+ def fetch_stall_state(self) -> Any | None:
174
+ """Fetch the current learning-stall snapshot from reflexio."""
175
+ client = self._get_client()
176
+ if client is None:
177
+ return None
178
+ try:
179
+ return client.get_stall_state()
180
+ except Exception as exc: # noqa: BLE001
181
+ _LOGGER.debug("get_stall_state failed: %s", exc)
182
+ return None
183
+
184
+ def mark_stall_notified(self) -> None:
185
+ """Idempotently flip ``notified_in_cc`` on the active stall row."""
186
+ client = self._get_client()
187
+ if client is None:
188
+ return
189
+ try:
190
+ client.mark_stall_notified()
191
+ except Exception as exc: # noqa: BLE001
192
+ _LOGGER.debug("mark_stall_notified failed: %s", exc)
193
+
194
+ # -----------------------------------------------------------------
195
+ # Broad reads (used by /show)
196
+ # -----------------------------------------------------------------
197
+
198
+ def fetch_user_playbooks(self, *, project_id: str, top_k: int = 10) -> list[Any]:
199
+ """Fetch CURRENT user playbooks for ``project_id``."""
200
+ client = self._get_client()
201
+ if client is None:
202
+ return []
203
+ try:
204
+ response = client.search_user_playbooks(
205
+ user_id=project_id,
206
+ status_filter=[None], # None => CURRENT in reflexio's filter API
207
+ top_k=top_k,
208
+ )
209
+ except Exception as exc: # noqa: BLE001
210
+ _LOGGER.debug("search_user_playbooks failed: %s", exc)
211
+ return []
212
+ return _extract_items(response, "user_playbooks")
213
+
214
+ def fetch_agent_playbooks(self, top_k: int = 10) -> list[Any]:
215
+ """Fetch CURRENT agent playbooks globally (shared across projects).
216
+
217
+ Filter by ``agent_version`` so we only pull in playbooks produced by
218
+ openClaw sessions.
219
+ """
220
+ client = self._get_client()
221
+ if client is None:
222
+ return []
223
+ try:
224
+ response = client.search_agent_playbooks(
225
+ agent_version=runtime.agent_version(),
226
+ status_filter=[None],
227
+ top_k=top_k,
228
+ )
229
+ except Exception as exc: # noqa: BLE001
230
+ _LOGGER.debug("search_agent_playbooks failed: %s", exc)
231
+ return []
232
+ return _filter_rejected_agent_playbooks(
233
+ _extract_items(response, "agent_playbooks")
234
+ )
235
+
236
+ def fetch_project_profiles(self, project_id: str, top_k: int = 20) -> list[Any]:
237
+ """Fetch preferences extracted for this project (across sessions)."""
238
+ client = self._get_client()
239
+ if client is None:
240
+ return []
241
+ try:
242
+ response = client.search_user_profiles(
243
+ user_id=project_id,
244
+ query="",
245
+ top_k=top_k,
246
+ )
247
+ except Exception as exc: # noqa: BLE001
248
+ _LOGGER.debug("search_user_profiles failed: %s", exc)
249
+ return []
250
+ return _extract_items(response, "user_profiles")
251
+
252
+ # -----------------------------------------------------------------
253
+ # Query-aware unified search (used by before_tool_call / before_prompt_build)
254
+ # -----------------------------------------------------------------
255
+
256
+ def search_all(
257
+ self, *, project_id: str, query: str, top_k: int = 5
258
+ ) -> tuple[list[Any], list[Any], list[Any]]:
259
+ """Unified hybrid search → ``(user_playbooks, agent_playbooks, preferences)``."""
260
+ client = self._get_client()
261
+ if client is None:
262
+ return [], [], []
263
+ try:
264
+ response = client.search(
265
+ query=query,
266
+ user_id=project_id,
267
+ agent_version=runtime.agent_version(),
268
+ entity_types=list(_UNIFIED_ENTITY_TYPES),
269
+ agent_playbook_status_filter=list(_AGENT_PLAYBOOK_APPROVAL_STATUSES),
270
+ enable_agent_answer=False,
271
+ top_k=top_k,
272
+ search_mode=_SEARCH_MODE_HYBRID,
273
+ )
274
+ except Exception as exc: # noqa: BLE001
275
+ _LOGGER.debug("unified search failed: %s", exc)
276
+ return [], [], []
277
+ return (
278
+ _extract_items(response, "user_playbooks"),
279
+ _filter_rejected_agent_playbooks(
280
+ _extract_items(response, "agent_playbooks")
281
+ ),
282
+ _extract_items(response, "profiles"),
283
+ )
284
+
285
+ # -----------------------------------------------------------------
286
+ # Broad fetch for explicit audit views (no query → can't use unified /api/search)
287
+ # -----------------------------------------------------------------
288
+
289
+ def fetch_all(
290
+ self,
291
+ *,
292
+ project_id: str,
293
+ user_playbook_top_k: int = 10,
294
+ agent_playbook_top_k: int = 10,
295
+ profile_top_k: int = 20,
296
+ ) -> tuple[list[Any], list[Any], list[Any]]:
297
+ """Parallel broad fetch for /show → ``(user_playbooks, agent_playbooks, preferences)``."""
298
+ with ThreadPoolExecutor(max_workers=3) as pool:
299
+ up_future = pool.submit(
300
+ self.fetch_user_playbooks,
301
+ project_id=project_id,
302
+ top_k=user_playbook_top_k,
303
+ )
304
+ ap_future = pool.submit(self.fetch_agent_playbooks, agent_playbook_top_k)
305
+ pr_future = pool.submit(
306
+ self.fetch_project_profiles, project_id, profile_top_k
307
+ )
308
+ return up_future.result(), ap_future.result(), pr_future.result()
309
+
310
+
311
+ def _extract_items(response: Any, field: str) -> list[Any]:
312
+ """Pull a list field from a reflexio response object or dict, tolerating shape drift."""
313
+ if response is None:
314
+ return []
315
+ if isinstance(response, dict):
316
+ value = response.get(field)
317
+ else:
318
+ value = getattr(response, field, None)
319
+ return list(value) if value else []
320
+
321
+
322
+ def _filter_rejected_agent_playbooks(items: list[Any]) -> list[Any]:
323
+ """Drop rejected shared skills defensively, even if an older backend ignores filters."""
324
+ return [
325
+ item
326
+ for item in items
327
+ if _agent_playbook_status(item) != _REJECTED_AGENT_PLAYBOOK_STATUS
328
+ ]
329
+
330
+
331
+ def _agent_playbook_status(item: Any) -> str:
332
+ if isinstance(item, dict):
333
+ value = item.get("playbook_status")
334
+ else:
335
+ value = getattr(item, "playbook_status", None)
336
+ return str(value or "").lower()
@@ -0,0 +1,47 @@
1
+ """Host/runtime state shared by openclaw-smart entrypoints.
2
+
3
+ openclaw-smart only runs in the openClaw context — there is no Claude Code
4
+ or Codex variant — but we keep ``set_host``/``host`` for symmetry with the
5
+ claude-smart API and to leave room for additional hosts in the future. The
6
+ reflexio ``agent_version`` is hardcoded so all openClaw projects roll up
7
+ into the same shared-learning bucket.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import os
13
+
14
+ HOST_ENV = "OPENCLAW_SMART_HOST"
15
+
16
+ HOST_OPENCLAW = "openclaw"
17
+ VALID_HOSTS = frozenset({HOST_OPENCLAW})
18
+
19
+ _AGENT_VERSION = "openclaw"
20
+ _current_host: str | None = None
21
+
22
+
23
+ def set_host(value: str | None) -> str:
24
+ """Set the current host, returning the normalized value."""
25
+ global _current_host
26
+ host_value = value if value in VALID_HOSTS else HOST_OPENCLAW
27
+ _current_host = host_value
28
+ os.environ[HOST_ENV] = host_value
29
+ return host_value
30
+
31
+
32
+ def host() -> str:
33
+ """Return the current host, defaulting to openClaw."""
34
+ if _current_host is not None:
35
+ return _current_host
36
+ value = os.environ.get(HOST_ENV)
37
+ return value if value in VALID_HOSTS else HOST_OPENCLAW
38
+
39
+
40
+ def is_openclaw() -> bool:
41
+ """True when the current hook invocation came from openClaw."""
42
+ return host() == HOST_OPENCLAW
43
+
44
+
45
+ def agent_version() -> str:
46
+ """Reflexio agent version used for cross-project openClaw learning."""
47
+ return _AGENT_VERSION
@@ -0,0 +1,61 @@
1
+ """Render the 1-line session_start banner for a credit/auth stall.
2
+
3
+ The template branches on the stall reason; output goes through openClaw's
4
+ ``prependContext`` so the model sees it once per stall event.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime
10
+ from typing import Literal
11
+
12
+ StallReason = Literal["billing_error", "auth_error"]
13
+
14
+ _DASHBOARD = "localhost:3001"
15
+
16
+
17
+ def render_banner(*, reason: str | None, reset_estimate: datetime | None) -> str:
18
+ """Format the session_start banner for the given stall reason.
19
+
20
+ Args:
21
+ reason (str | None): ``"billing_error"`` or ``"auth_error"``. Other
22
+ values (including ``None``) yield an empty string so callers can
23
+ pass raw DB values safely.
24
+ reset_estimate (datetime | None): Best-effort credit reset time;
25
+ included in the billing-error banner when present.
26
+
27
+ Returns:
28
+ str: A single-line banner, or ``""`` for unknown reasons.
29
+ """
30
+ match reason:
31
+ case "billing_error":
32
+ if reset_estimate is None:
33
+ return (
34
+ f"openclaw-smart: learning paused — Agent SDK credit "
35
+ f"exhausted. Details: {_DASHBOARD}"
36
+ )
37
+ return (
38
+ f"openclaw-smart: learning paused — Agent SDK credit "
39
+ f"exhausted (resets ~{_format_reset(reset_estimate)}). "
40
+ f"Details: {_DASHBOARD}"
41
+ )
42
+ case "auth_error":
43
+ return (
44
+ f"openclaw-smart: learning paused — please run /login. "
45
+ f"Details: {_DASHBOARD}"
46
+ )
47
+ case _:
48
+ return ""
49
+
50
+
51
+ def _format_reset(value: datetime) -> str:
52
+ """Format a reset datetime as e.g. ``Jun 12 9:00`` for the banner.
53
+
54
+ Args:
55
+ value (datetime): The reset time to format.
56
+
57
+ Returns:
58
+ str: The banner-friendly representation, with the hour shown
59
+ without a leading zero (e.g. ``Jun 12 9:00``).
60
+ """
61
+ return f"{value.strftime('%b %d')} {value.hour}:{value.minute:02d}"