claude-smart 0.2.42 → 0.2.44

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 (402) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/README.md +1 -1
  3. package/bin/claude-smart.js +2 -2
  4. package/package.json +9 -3
  5. package/plugin/.claude-plugin/plugin.json +9 -3
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +23 -3
  8. package/plugin/pyproject.toml +3 -3
  9. package/plugin/scripts/_lib.sh +91 -0
  10. package/plugin/scripts/backend-service.sh +51 -4
  11. package/plugin/scripts/cli.sh +3 -1
  12. package/plugin/scripts/codex-hook.js +72 -4
  13. package/plugin/scripts/dashboard-build.sh +1 -0
  14. package/plugin/scripts/dashboard-service.sh +1 -0
  15. package/plugin/scripts/ensure-plugin-root.sh +1 -0
  16. package/plugin/scripts/hook_entry.sh +6 -3
  17. package/plugin/scripts/smart-install.sh +3 -2
  18. package/plugin/src/README.md +57 -0
  19. package/plugin/src/claude_smart/context_format.py +11 -12
  20. package/plugin/src/claude_smart/cs_cite.py +26 -12
  21. package/plugin/src/claude_smart/ids.py +13 -5
  22. package/plugin/uv.lock +126 -5
  23. package/plugin/vendor/reflexio/.env.example +62 -0
  24. package/plugin/vendor/reflexio/LICENSE +201 -0
  25. package/plugin/vendor/reflexio/README.md +338 -0
  26. package/plugin/vendor/reflexio/pyproject.toml +274 -0
  27. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  28. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  29. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  37. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  38. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  39. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  40. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +265 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +964 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  68. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  69. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  70. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  71. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  72. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  73. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  74. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  75. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  148. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  149. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  150. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  151. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  162. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  163. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  164. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  165. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  166. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1112 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +768 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  180. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  181. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  182. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +333 -0
  183. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  184. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  185. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  186. package/plugin/vendor/reflexio/reflexio/server/README.md +622 -0
  187. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  188. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  189. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  190. package/plugin/vendor/reflexio/reflexio/server/api.py +2868 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +34 -0
  192. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
  193. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
  194. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
  195. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
  196. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +562 -0
  197. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
  198. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
  199. package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
  200. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
  201. package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
  202. package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
  203. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +359 -0
  204. package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
  205. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1871 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +140 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +479 -0
  208. package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
  209. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
  210. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
  211. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +338 -0
  212. package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
  213. package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +288 -0
  214. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
  215. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +187 -0
  216. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
  217. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +716 -0
  218. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
  219. package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
  220. package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
  221. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
  222. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
  223. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
  224. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
  225. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
  226. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
  227. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
  228. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
  229. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
  230. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
  231. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
  232. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
  233. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
  234. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
  235. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
  236. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
  237. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
  238. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
  239. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
  240. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
  241. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
  242. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
  243. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
  244. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.1.prompt.md +69 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +71 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +283 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.2.prompt.md +234 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +244 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +137 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  276. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  277. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  278. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  279. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  280. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  281. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  282. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  283. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/README.md +58 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +336 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1668 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/embedding_text.py +62 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +358 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +535 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +779 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +94 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +702 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +1045 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +772 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +737 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +803 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +80 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +756 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1298 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +384 -0
  380. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  381. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  382. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  383. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  384. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  385. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  386. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  387. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  388. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  389. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +572 -0
  390. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  391. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  392. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  393. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  394. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  395. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  396. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  397. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  398. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  399. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  400. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  401. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  402. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,197 @@
1
+ """Parse the NDJSON stream from ``claude -p --output-format stream-json``
2
+ and classify whether the call ended in a credit/auth stall.
3
+
4
+ Public surface:
5
+ - parse_stream_json(stdout, exit_code, stderr_text) -> ParseResult
6
+ - classify_stall(result) -> "billing_error" | "auth_error" | None
7
+ - parse_reset_estimate(text) -> datetime | None
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import logging
14
+ import re
15
+ from dataclasses import dataclass, field
16
+ from datetime import UTC, datetime, time, timedelta
17
+
18
+ from reflexio.models.api_schema.stall_state_schema import StallReason
19
+
20
+ _LOGGER = logging.getLogger(__name__)
21
+
22
+ _BILLING_CATEGORIES = {"billing_error"}
23
+ _AUTH_CATEGORIES = {"authentication_failed", "oauth_org_not_allowed"}
24
+
25
+ _TEXT_PATTERNS_BILLING = (
26
+ "hit your weekly limit",
27
+ "hit your session limit",
28
+ "credit balance is too low",
29
+ "billing_error",
30
+ )
31
+ _TEXT_PATTERNS_AUTH = (
32
+ "please run /login",
33
+ "oauth token revoked",
34
+ "oauth token has expired",
35
+ "not logged in",
36
+ )
37
+
38
+ _RESET_RE = re.compile(
39
+ r"resets\s+(?:(?P<weekday>mon|tue|wed|thu|fri|sat|sun)\w*\s+)?"
40
+ r"(?P<hour>\d{1,2}):(?P<minute>\d{2})\s*(?P<ampm>am|pm)",
41
+ re.IGNORECASE,
42
+ )
43
+
44
+
45
+ @dataclass
46
+ class ParseResult:
47
+ """Aggregated state of one ``claude -p`` invocation.
48
+
49
+ Attributes:
50
+ success (bool): True iff exit_code==0 AND a terminal result event
51
+ with non-empty text appeared.
52
+ terminal_text (str): The ``result`` field from the terminal event.
53
+ retry_errors (list[str]): All ``error`` strings observed in
54
+ ``api_retry`` events, in order.
55
+ stderr_text (str): Raw stderr text from the subprocess.
56
+ raw_lines_parsed (int): NDJSON lines parsed successfully.
57
+ raw_lines_failed (int): NDJSON lines that failed to parse.
58
+ """
59
+
60
+ success: bool
61
+ terminal_text: str
62
+ retry_errors: list[str] = field(default_factory=list)
63
+ stderr_text: str = ""
64
+ raw_lines_parsed: int = 0
65
+ raw_lines_failed: int = 0
66
+
67
+ @property
68
+ def stall_candidate(self) -> str | None:
69
+ """The last retry error string in a stall category, or None."""
70
+ for err in reversed(self.retry_errors):
71
+ if err in _BILLING_CATEGORIES or err in _AUTH_CATEGORIES:
72
+ return err
73
+ return None
74
+
75
+
76
+ def parse_stream_json(
77
+ stdout: str,
78
+ *,
79
+ exit_code: int,
80
+ stderr_text: str = "",
81
+ ) -> ParseResult:
82
+ """Parse the full NDJSON stream from claude -p.
83
+
84
+ Args:
85
+ stdout (str): Raw subprocess stdout — newline-delimited JSON events.
86
+ exit_code (int): Subprocess exit code.
87
+ stderr_text (str): Raw stderr — used by the text-fallback path.
88
+
89
+ Returns:
90
+ ParseResult: Aggregated state. ``success`` requires both a clean
91
+ exit and a parseable terminal ``result`` event.
92
+ """
93
+ retry_errors: list[str] = []
94
+ terminal_text = ""
95
+ parsed = 0
96
+ failed = 0
97
+ saw_terminal = False
98
+ for line in stdout.splitlines():
99
+ if not line.strip():
100
+ continue
101
+ try:
102
+ event = json.loads(line)
103
+ except json.JSONDecodeError:
104
+ failed += 1
105
+ continue
106
+ parsed += 1
107
+ if not isinstance(event, dict):
108
+ continue
109
+ match event.get("type"), event.get("subtype"):
110
+ case ("system", "api_retry"):
111
+ err = event.get("error")
112
+ if isinstance(err, str):
113
+ retry_errors.append(err)
114
+ case ("result", _) | (_, "result"):
115
+ text = event.get("result")
116
+ if isinstance(text, str):
117
+ terminal_text = text
118
+ saw_terminal = True
119
+ return ParseResult(
120
+ success=(exit_code == 0 and saw_terminal and bool(terminal_text)),
121
+ terminal_text=terminal_text,
122
+ retry_errors=retry_errors,
123
+ stderr_text=stderr_text,
124
+ raw_lines_parsed=parsed,
125
+ raw_lines_failed=failed,
126
+ )
127
+
128
+
129
+ def classify_stall(result: ParseResult) -> StallReason | None:
130
+ """Decide whether a finished ParseResult represents a stall.
131
+
132
+ Args:
133
+ result (ParseResult): Output of :func:`parse_stream_json`.
134
+
135
+ Returns:
136
+ StallReason | None: ``"billing_error"`` or ``"auth_error"`` only
137
+ when the call terminated unsuccessfully AND a stall-class
138
+ signal was observed (event or text fallback).
139
+ """
140
+ if result.success:
141
+ return None
142
+ candidate = result.stall_candidate
143
+ if candidate in _BILLING_CATEGORIES:
144
+ return "billing_error"
145
+ if candidate in _AUTH_CATEGORIES:
146
+ return "auth_error"
147
+ return _classify_from_text(result.stderr_text + " " + result.terminal_text)
148
+
149
+
150
+ def _classify_from_text(text: str) -> StallReason | None:
151
+ """Belt-and-suspenders: regex the raw error text after NDJSON has been parsed."""
152
+ lower = text.lower()
153
+ if any(p in lower for p in _TEXT_PATTERNS_BILLING):
154
+ _LOGGER.warning("Stall classified via text fallback (billing): %r", text[:200])
155
+ return "billing_error"
156
+ if any(p in lower for p in _TEXT_PATTERNS_AUTH):
157
+ _LOGGER.warning("Stall classified via text fallback (auth): %r", text[:200])
158
+ return "auth_error"
159
+ return None
160
+
161
+
162
+ def parse_reset_estimate(text: str) -> datetime | None:
163
+ """Best-effort parse of a reset time from Claude Code error text.
164
+
165
+ The hour/minute extracted from the message text is treated as UTC, then
166
+ advanced one day if it has already passed. Claude Code's error messages
167
+ typically express reset times in the user's local timezone, so the
168
+ returned datetime may be off by the user's UTC offset (up to ±24h).
169
+ Callers should treat this as an approximation, not an authoritative
170
+ reset moment.
171
+
172
+ Args:
173
+ text (str): Error text — typically the terminal event message or stderr.
174
+
175
+ Returns:
176
+ datetime | None: A UTC-naive-in-spirit but tz-aware datetime that
177
+ best approximates the next reset, or None when no recognizable
178
+ pattern is found.
179
+ """
180
+ match = _RESET_RE.search(text or "")
181
+ if not match:
182
+ return None
183
+ hour_raw = int(match.group("hour"))
184
+ minute = int(match.group("minute"))
185
+ # The regex permits 1–2 digit hours and minutes; reject out-of-range
186
+ # values so "13:00pm" or "10:75am" parse as None instead of producing
187
+ # silently-wrong times via modulo arithmetic.
188
+ if not 1 <= hour_raw <= 12 or not 0 <= minute <= 59:
189
+ return None
190
+ hour = hour_raw % 12
191
+ if match.group("ampm").lower() == "pm":
192
+ hour += 12
193
+ today = datetime.now(UTC).date()
194
+ candidate = datetime.combine(today, time(hour, minute), tzinfo=UTC)
195
+ if candidate <= datetime.now(UTC):
196
+ candidate += timedelta(days=1)
197
+ return candidate
@@ -0,0 +1,338 @@
1
+ """HTTP embedding service provider.
2
+
3
+ This module is the routing boundary between Reflexio's LLM client and an
4
+ OpenAI-compatible embedding service. It lets local Claude Smart installs keep
5
+ one model process alive across backend workers, Claude Code, and Codex, while
6
+ also supporting a horizontally-scaled internal service in cloud deployments.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import logging
13
+ import os
14
+ import time
15
+ from typing import Any, Literal
16
+
17
+ import httpx
18
+
19
+ _LOGGER = logging.getLogger(__name__)
20
+
21
+ EmbeddingProviderMode = Literal[
22
+ "cloud", "local_service", "internal_service", "inprocess", "off"
23
+ ]
24
+
25
+ _ENV_PROVIDER = "REFLEXIO_EMBEDDING_PROVIDER"
26
+ _ENV_SERVICE_URL = "REFLEXIO_EMBEDDING_SERVICE_URL"
27
+ _ENV_TIMEOUT_MS = "REFLEXIO_EMBEDDING_SERVICE_TIMEOUT_MS"
28
+ _ENV_EMBEDDING_PORT = "EMBEDDING_PORT"
29
+ _ENV_DAEMON_HOST = "REFLEXIO_EMBEDDING_DAEMON_HOST"
30
+ _ENV_LOCAL_SERVICE_PROBE_TIMEOUT_MS = (
31
+ "REFLEXIO_EMBEDDING_LOCAL_SERVICE_PROBE_TIMEOUT_MS"
32
+ )
33
+ _ENV_CLAUDE_SMART_LOCAL = "CLAUDE_SMART_USE_LOCAL_EMBEDDING"
34
+ _ENV_MAX_TEXTS_PER_REQUEST = "REFLEXIO_EMBEDDING_SERVICE_MAX_TEXTS_PER_REQUEST"
35
+ _DEFAULT_LOCAL_PORT = 8072
36
+ _DEFAULT_INTERNAL_SERVICE_TIMEOUT_MS = 2_000
37
+ _DEFAULT_LOCAL_SERVICE_TIMEOUT_MS = 30_000
38
+ _DEFAULT_LOCAL_SERVICE_PROBE_TIMEOUT_MS = 200
39
+ # Each request embeds its whole ``input`` list in one ``model.encode()`` on the
40
+ # service, so an unbounded request can exceed the client read timeout on a CPU
41
+ # daemon. Cap texts per request and concatenate; encode batching is a separate
42
+ # server-side knob (REFLEXIO_EMBED_BATCH_SIZE).
43
+ _DEFAULT_MAX_TEXTS_PER_REQUEST = 32
44
+ _LOCAL_SERVICE_PROBE_CACHE_SECONDS = 5.0
45
+ _SERVICE_MODES = {"local_service", "internal_service"}
46
+ _VALID_MODES = {"cloud", *_SERVICE_MODES, "inprocess", "off"}
47
+ _local_service_probe_cache: tuple[float, bool, str | None] | None = None
48
+
49
+
50
+ class EmbeddingUnavailableError(RuntimeError):
51
+ """Raised when the configured embedding provider is unavailable."""
52
+
53
+
54
+ def _local_service_url() -> str:
55
+ host = os.environ.get(_ENV_DAEMON_HOST, "").strip() or "127.0.0.1"
56
+ port = os.environ.get(_ENV_EMBEDDING_PORT, str(_DEFAULT_LOCAL_PORT))
57
+ return f"http://{host}:{port}"
58
+
59
+
60
+ def _local_service_probe_timeout_seconds() -> float:
61
+ raw = os.environ.get(_ENV_LOCAL_SERVICE_PROBE_TIMEOUT_MS)
62
+ if raw is None:
63
+ return _DEFAULT_LOCAL_SERVICE_PROBE_TIMEOUT_MS / 1000
64
+ try:
65
+ timeout_ms = int(raw)
66
+ except ValueError:
67
+ _LOGGER.warning(
68
+ "%s must be an integer number of milliseconds; using %dms",
69
+ _ENV_LOCAL_SERVICE_PROBE_TIMEOUT_MS,
70
+ _DEFAULT_LOCAL_SERVICE_PROBE_TIMEOUT_MS,
71
+ )
72
+ return _DEFAULT_LOCAL_SERVICE_PROBE_TIMEOUT_MS / 1000
73
+ return max(timeout_ms, 1) / 1000
74
+
75
+
76
+ def embedding_service_url(mode: EmbeddingProviderMode | None = None) -> str:
77
+ """Return the configured embedding service URL.
78
+
79
+ ``local_service`` defaults to ``127.0.0.1:$EMBEDDING_PORT`` so local
80
+ Claude Smart hosts can share a single machine daemon. ``internal_service``
81
+ requires an explicit URL because it is deployment-specific.
82
+ """
83
+ resolved = mode or embedding_provider_mode()
84
+ configured = os.environ.get(_ENV_SERVICE_URL)
85
+ if configured:
86
+ return configured.rstrip("/")
87
+ if resolved == "local_service":
88
+ return _local_service_url()
89
+ raise EmbeddingUnavailableError(
90
+ f"{_ENV_SERVICE_URL} is required when {_ENV_PROVIDER}={resolved}"
91
+ )
92
+
93
+
94
+ def embedding_service_timeout_seconds(
95
+ mode: EmbeddingProviderMode | None = None,
96
+ ) -> float:
97
+ raw = os.environ.get(_ENV_TIMEOUT_MS)
98
+ if raw is None:
99
+ resolved = mode or embedding_provider_mode()
100
+ if resolved == "local_service":
101
+ return _DEFAULT_LOCAL_SERVICE_TIMEOUT_MS / 1000
102
+ return _DEFAULT_INTERNAL_SERVICE_TIMEOUT_MS / 1000
103
+ try:
104
+ timeout_ms = int(raw)
105
+ except ValueError as exc:
106
+ raise EmbeddingUnavailableError(
107
+ f"{_ENV_TIMEOUT_MS} must be an integer number of milliseconds"
108
+ ) from exc
109
+ return max(timeout_ms, 1) / 1000
110
+
111
+
112
+ def _is_local_model(model: str | None) -> bool:
113
+ return bool(model and model.startswith("local/"))
114
+
115
+
116
+ def _local_service_status() -> tuple[bool, str | None]:
117
+ global _local_service_probe_cache
118
+ now = time.monotonic()
119
+ if (
120
+ _local_service_probe_cache is not None
121
+ and now - _local_service_probe_cache[0] < _LOCAL_SERVICE_PROBE_CACHE_SECONDS
122
+ ):
123
+ return _local_service_probe_cache[1], _local_service_probe_cache[2]
124
+
125
+ try:
126
+ response = httpx.get(
127
+ f"{_local_service_url()}/health",
128
+ timeout=_local_service_probe_timeout_seconds(),
129
+ )
130
+ reachable = response.status_code < 500
131
+ active_model = response.json().get("active_model") if reachable else None
132
+ if not isinstance(active_model, str):
133
+ active_model = None
134
+ except httpx.HTTPError:
135
+ reachable = False
136
+ active_model = None
137
+ except ValueError:
138
+ reachable = False
139
+ active_model = None
140
+ _local_service_probe_cache = (now, reachable, active_model)
141
+ return reachable, active_model
142
+
143
+
144
+ def _local_service_supports_model(model: str | None) -> bool:
145
+ reachable, active_model = _local_service_status()
146
+ return reachable and (active_model is None or active_model == model)
147
+
148
+
149
+ def _ordered_embeddings_from_response(
150
+ data: Any, expected_count: int
151
+ ) -> list[list[float]]:
152
+ if not isinstance(data, list):
153
+ raise ValueError("embedding service response is missing data[]")
154
+ if len(data) != expected_count:
155
+ raise ValueError(
156
+ "embedding service response cardinality mismatch: "
157
+ f"expected {expected_count}, got {len(data)}"
158
+ )
159
+
160
+ seen: set[int] = set()
161
+ indexed_embeddings: list[tuple[int, list[Any]]] = []
162
+ for item in data:
163
+ if not isinstance(item, dict):
164
+ raise ValueError("embedding service response data[] has invalid item")
165
+
166
+ index = item.get("index")
167
+ if type(index) is not int:
168
+ raise ValueError("embedding service response has invalid index")
169
+ if index in seen:
170
+ raise ValueError(f"embedding service response has duplicate index {index}")
171
+ seen.add(index)
172
+
173
+ embedding = item.get("embedding")
174
+ if not isinstance(embedding, list):
175
+ raise ValueError("embedding service response has invalid embeddings")
176
+ indexed_embeddings.append((index, embedding))
177
+
178
+ expected_indices = set(range(expected_count))
179
+ if seen != expected_indices:
180
+ raise ValueError(
181
+ "embedding service response indices mismatch: "
182
+ f"expected {sorted(expected_indices)}, got {sorted(seen)}"
183
+ )
184
+
185
+ return [
186
+ [float(value) for value in embedding]
187
+ for _, embedding in sorted(indexed_embeddings)
188
+ ]
189
+
190
+
191
+ def embedding_provider_mode(model: str | None = None) -> EmbeddingProviderMode:
192
+ """Resolve the embedding provider mode for a model.
193
+
194
+ Explicit legacy env modes keep their historical behavior. With no explicit
195
+ env mode, routing is model-driven: ``local/*`` uses the local daemon when it
196
+ is reachable and otherwise falls back to the in-process embedder; cloud
197
+ models use their provider directly.
198
+ """
199
+ configured = os.environ.get(_ENV_PROVIDER)
200
+ if configured:
201
+ mode = configured.strip().lower()
202
+ if mode not in _VALID_MODES:
203
+ raise EmbeddingUnavailableError(
204
+ f"Invalid {_ENV_PROVIDER}={configured!r}; expected one of "
205
+ f"{', '.join(sorted(_VALID_MODES))}"
206
+ )
207
+ return mode # type: ignore[return-value]
208
+
209
+ if os.environ.get(_ENV_CLAUDE_SMART_LOCAL) == "1":
210
+ return "local_service"
211
+
212
+ if os.environ.get(_ENV_SERVICE_URL):
213
+ return "internal_service"
214
+
215
+ if _is_local_model(model):
216
+ return "local_service" if _local_service_supports_model(model) else "inprocess"
217
+ return "cloud"
218
+
219
+
220
+ def should_use_embedding_service(model: str) -> bool:
221
+ """Return True when embedding requests should call the HTTP service."""
222
+ return embedding_provider_mode(model) in _SERVICE_MODES
223
+
224
+
225
+ def get_service_embeddings(
226
+ texts: list[str],
227
+ *,
228
+ model: str,
229
+ dimensions: int | None = None,
230
+ ) -> list[list[float]]:
231
+ """Call the OpenAI-compatible embedding service.
232
+
233
+ Args:
234
+ texts: Inputs to embed.
235
+ model: Embedding model name.
236
+ dimensions: Optional embedding dimensions.
237
+
238
+ Returns:
239
+ Embeddings in input order.
240
+
241
+ Raises:
242
+ EmbeddingUnavailableError: If the service cannot be reached or returns
243
+ an invalid response.
244
+ """
245
+ if not texts:
246
+ return []
247
+
248
+ mode = embedding_provider_mode(model)
249
+ if mode == "off":
250
+ raise EmbeddingUnavailableError("Embedding provider is disabled")
251
+ if mode not in _SERVICE_MODES:
252
+ raise EmbeddingUnavailableError(
253
+ f"Embedding service requested while {_ENV_PROVIDER}={mode}"
254
+ )
255
+
256
+ url = f"{embedding_service_url(mode)}/v1/embeddings"
257
+ timeout = embedding_service_timeout_seconds(mode)
258
+
259
+ # Bound each request so a single large publish cannot exceed the client read
260
+ # timeout: split into fixed-size chunks and concatenate the results in order.
261
+ chunk_size = _max_texts_per_request()
262
+ embeddings: list[list[float]] = []
263
+ for start in range(0, len(texts), chunk_size):
264
+ chunk = texts[start : start + chunk_size]
265
+ embeddings.extend(
266
+ _post_embedding_batch(
267
+ url, model=model, texts=chunk, dimensions=dimensions, timeout=timeout
268
+ )
269
+ )
270
+ return embeddings
271
+
272
+
273
+ def _post_embedding_batch(
274
+ url: str,
275
+ *,
276
+ model: str,
277
+ texts: list[str],
278
+ dimensions: int | None,
279
+ timeout: float,
280
+ ) -> list[list[float]]:
281
+ """POST one bounded batch of texts to the embedding service."""
282
+ payload: dict[str, Any] = {"model": model, "input": texts}
283
+ if dimensions:
284
+ payload["dimensions"] = dimensions
285
+
286
+ last_error: Exception | None = None
287
+ for attempt in range(2):
288
+ try:
289
+ with httpx.Client(timeout=timeout) as client:
290
+ response = client.post(url, json=payload)
291
+ response.raise_for_status()
292
+ body = response.json()
293
+ return _ordered_embeddings_from_response(body.get("data"), len(texts))
294
+ except (httpx.ConnectError, httpx.ConnectTimeout) as exc:
295
+ # Connection never established — the request never reached the
296
+ # server, so a single retry is safe and cannot duplicate work.
297
+ last_error = exc
298
+ if attempt == 0:
299
+ time.sleep(0.1)
300
+ except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
301
+ # The server already received the request: a read timeout means it
302
+ # is still encoding, and retrying would queue a second identical
303
+ # encode behind the first and amplify load on an already-saturated
304
+ # daemon. HTTPStatusError (4xx/5xx) and malformed-payload errors
305
+ # (JSONDecodeError / the ValueError raised by
306
+ # _ordered_embeddings_from_response) will not change on retry
307
+ # either. Fail fast. Anything outside this set (AttributeError,
308
+ # TypeError, ...) is a programming bug and propagates raw.
309
+ last_error = exc
310
+ break
311
+
312
+ _LOGGER.warning("Embedding service unavailable at %s: %s", url, last_error)
313
+ raise EmbeddingUnavailableError(
314
+ f"Embedding service unavailable at {url}: {last_error}"
315
+ ) from last_error
316
+
317
+
318
+ def _max_texts_per_request() -> int:
319
+ raw = os.environ.get(_ENV_MAX_TEXTS_PER_REQUEST)
320
+ if raw is None:
321
+ return _DEFAULT_MAX_TEXTS_PER_REQUEST
322
+ try:
323
+ value = int(raw)
324
+ except ValueError:
325
+ _LOGGER.warning(
326
+ "%s must be an integer; using %d",
327
+ _ENV_MAX_TEXTS_PER_REQUEST,
328
+ _DEFAULT_MAX_TEXTS_PER_REQUEST,
329
+ )
330
+ return _DEFAULT_MAX_TEXTS_PER_REQUEST
331
+ if value < 1:
332
+ _LOGGER.warning(
333
+ "%s must be >= 1; using %d",
334
+ _ENV_MAX_TEXTS_PER_REQUEST,
335
+ _DEFAULT_MAX_TEXTS_PER_REQUEST,
336
+ )
337
+ return _DEFAULT_MAX_TEXTS_PER_REQUEST
338
+ return value