claude-smart 0.2.41 → 0.2.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/README.md +1 -1
  3. package/bin/claude-smart.js +86 -48
  4. package/package.json +10 -3
  5. package/plugin/.claude-plugin/plugin.json +9 -3
  6. package/plugin/.codex-plugin/plugin.json +1 -1
  7. package/plugin/README.md +2 -2
  8. package/plugin/dashboard/next.config.ts +9 -1
  9. package/plugin/pyproject.toml +2 -2
  10. package/plugin/scripts/_lib.sh +91 -0
  11. package/plugin/scripts/backend-service.sh +46 -15
  12. package/plugin/scripts/cli.sh +29 -1
  13. package/plugin/scripts/codex-hook.js +72 -4
  14. package/plugin/scripts/dashboard-build.sh +1 -0
  15. package/plugin/scripts/dashboard-service.sh +1 -0
  16. package/plugin/scripts/ensure-plugin-root.sh +7 -14
  17. package/plugin/scripts/hook_entry.sh +1 -0
  18. package/plugin/scripts/smart-install.sh +18 -2
  19. package/plugin/src/claude_smart/cli.py +72 -38
  20. package/plugin/src/claude_smart/context_format.py +11 -12
  21. package/plugin/src/claude_smart/cs_cite.py +26 -12
  22. package/plugin/src/claude_smart/ids.py +13 -5
  23. package/plugin/uv.lock +1 -1
  24. package/plugin/vendor/reflexio/.env.example +53 -0
  25. package/plugin/vendor/reflexio/LICENSE +201 -0
  26. package/plugin/vendor/reflexio/README.md +338 -0
  27. package/plugin/vendor/reflexio/pyproject.toml +271 -0
  28. package/plugin/vendor/reflexio/reflexio/README.md +184 -0
  29. package/plugin/vendor/reflexio/reflexio/__init__.py +166 -0
  30. package/plugin/vendor/reflexio/reflexio/benchmarks/__init__.py +1 -0
  31. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/README.md +109 -0
  32. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/__init__.py +1 -0
  33. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/backends.py +175 -0
  34. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/bench.py +642 -0
  35. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/embed_cache.py +330 -0
  36. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/report.py +317 -0
  37. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/report.md +43 -0
  38. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/results/results.json +4478 -0
  39. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/scenarios.py +134 -0
  40. package/plugin/vendor/reflexio/reflexio/benchmarks/retrieval_latency/seed.py +255 -0
  41. package/plugin/vendor/reflexio/reflexio/cli/README.md +287 -0
  42. package/plugin/vendor/reflexio/reflexio/cli/__init__.py +0 -0
  43. package/plugin/vendor/reflexio/reflexio/cli/__main__.py +56 -0
  44. package/plugin/vendor/reflexio/reflexio/cli/_client.py +86 -0
  45. package/plugin/vendor/reflexio/reflexio/cli/app.py +127 -0
  46. package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +266 -0
  47. package/plugin/vendor/reflexio/reflexio/cli/codex_auth.py +503 -0
  48. package/plugin/vendor/reflexio/reflexio/cli/commands/__init__.py +0 -0
  49. package/plugin/vendor/reflexio/reflexio/cli/commands/admin_cmd.py +65 -0
  50. package/plugin/vendor/reflexio/reflexio/cli/commands/agent_playbooks.py +503 -0
  51. package/plugin/vendor/reflexio/reflexio/cli/commands/api.py +114 -0
  52. package/plugin/vendor/reflexio/reflexio/cli/commands/auth.py +109 -0
  53. package/plugin/vendor/reflexio/reflexio/cli/commands/config_cmd.py +511 -0
  54. package/plugin/vendor/reflexio/reflexio/cli/commands/doctor.py +127 -0
  55. package/plugin/vendor/reflexio/reflexio/cli/commands/embeddings.py +53 -0
  56. package/plugin/vendor/reflexio/reflexio/cli/commands/interactions.py +478 -0
  57. package/plugin/vendor/reflexio/reflexio/cli/commands/profiles.py +303 -0
  58. package/plugin/vendor/reflexio/reflexio/cli/commands/services.py +289 -0
  59. package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +961 -0
  60. package/plugin/vendor/reflexio/reflexio/cli/commands/shortcuts.py +285 -0
  61. package/plugin/vendor/reflexio/reflexio/cli/commands/status_cmd.py +143 -0
  62. package/plugin/vendor/reflexio/reflexio/cli/commands/user_playbooks.py +373 -0
  63. package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +284 -0
  64. package/plugin/vendor/reflexio/reflexio/cli/errors.py +217 -0
  65. package/plugin/vendor/reflexio/reflexio/cli/log_format.py +247 -0
  66. package/plugin/vendor/reflexio/reflexio/cli/output.py +867 -0
  67. package/plugin/vendor/reflexio/reflexio/cli/paths.py +41 -0
  68. package/plugin/vendor/reflexio/reflexio/cli/run_services.py +391 -0
  69. package/plugin/vendor/reflexio/reflexio/cli/state.py +204 -0
  70. package/plugin/vendor/reflexio/reflexio/cli/stop_services.py +96 -0
  71. package/plugin/vendor/reflexio/reflexio/cli/utils.py +329 -0
  72. package/plugin/vendor/reflexio/reflexio/client/__init__.py +3 -0
  73. package/plugin/vendor/reflexio/reflexio/client/cache.py +150 -0
  74. package/plugin/vendor/reflexio/reflexio/client/client.py +2613 -0
  75. package/plugin/vendor/reflexio/reflexio/defaults.py +23 -0
  76. package/plugin/vendor/reflexio/reflexio/integrations/__init__.py +0 -0
  77. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/.clawhubignore +7 -0
  78. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/README.md +274 -0
  79. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/TESTING.md +517 -0
  80. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/hook/handler.js +473 -0
  81. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package-lock.json +2156 -0
  82. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/package.json +18 -0
  83. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/handler.ts +241 -0
  84. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/hook/setup.ts +140 -0
  85. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/index.ts +130 -0
  86. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/publish.ts +113 -0
  87. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/search.ts +52 -0
  88. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/server.ts +103 -0
  89. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/sqlite-buffer.ts +156 -0
  90. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/lib/user-id.ts +134 -0
  91. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/openclaw.plugin.json +41 -0
  92. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/package.json +17 -0
  93. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/rules/reflexio.md +24 -0
  94. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/skills/reflexio/SKILL.md +48 -0
  95. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/publish_clawhub.sh +278 -0
  96. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/references/HOOK.md +164 -0
  97. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/install.sh +36 -0
  98. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/scripts/uninstall.sh +35 -0
  99. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/publish.test.ts +27 -0
  100. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/search.test.ts +31 -0
  101. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/server.test.ts +42 -0
  102. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/setup.test.ts +49 -0
  103. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/sqlite-buffer.test.ts +91 -0
  104. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tests/user-id.test.ts +50 -0
  105. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/tsconfig.json +16 -0
  106. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/types/openclaw.d.ts +230 -0
  107. package/plugin/vendor/reflexio/reflexio/integrations/openclaw/vitest.config.ts +13 -0
  108. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/README.md +120 -0
  109. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/TESTING.md +168 -0
  110. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package-lock.json +1657 -0
  111. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/package.json +16 -0
  112. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/HEARTBEAT.md +6 -0
  113. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/README.md +84 -0
  114. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/SKILL.md +194 -0
  115. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/_meta.json +6 -0
  116. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/agents/reflexio-extractor.md +45 -0
  117. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/handler.ts +214 -0
  118. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/hook/setup.ts +55 -0
  119. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/index.ts +327 -0
  120. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/consolidate.ts +233 -0
  121. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/dedup.ts +80 -0
  122. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/io.ts +155 -0
  123. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/openclaw-cli.ts +67 -0
  124. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/search.ts +33 -0
  125. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-playbook.ts +76 -0
  126. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/lib/write-profile.ts +79 -0
  127. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/openclaw.plugin.json +46 -0
  128. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/package.json +18 -0
  129. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/README.md +36 -0
  130. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/full_consolidation.md +56 -0
  131. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/playbook_extraction.md +217 -0
  132. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/prompts/profile_extraction.md +132 -0
  133. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-consolidate/SKILL.md +33 -0
  134. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/plugin/skills/reflexio-embedded/SKILL.md +194 -0
  135. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/HOOK.md +18 -0
  136. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/architecture.md +49 -0
  137. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/comparison.md +31 -0
  138. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/future-work.md +47 -0
  139. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/references/porting-notes.md +52 -0
  140. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/install.sh +52 -0
  141. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/scripts/uninstall.sh +36 -0
  142. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/consolidate.test.ts +135 -0
  143. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/dedup.test.ts +104 -0
  144. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/io.test.ts +175 -0
  145. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/search.test.ts +66 -0
  146. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/smoke-test.ts +140 -0
  147. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-playbook.test.ts +93 -0
  148. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tests/write-profile.test.ts +174 -0
  149. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/tsconfig.json +16 -0
  150. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/types/openclaw.d.ts +230 -0
  151. package/plugin/vendor/reflexio/reflexio/integrations/openclaw-embedded/vitest.config.ts +7 -0
  152. package/plugin/vendor/reflexio/reflexio/lib/__init__.py +23 -0
  153. package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +310 -0
  154. package/plugin/vendor/reflexio/reflexio/lib/_base.py +225 -0
  155. package/plugin/vendor/reflexio/reflexio/lib/_config.py +83 -0
  156. package/plugin/vendor/reflexio/reflexio/lib/_dashboard.py +266 -0
  157. package/plugin/vendor/reflexio/reflexio/lib/_generation.py +176 -0
  158. package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +334 -0
  159. package/plugin/vendor/reflexio/reflexio/lib/_operations.py +153 -0
  160. package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +545 -0
  161. package/plugin/vendor/reflexio/reflexio/lib/_reflection.py +52 -0
  162. package/plugin/vendor/reflexio/reflexio/lib/_search.py +167 -0
  163. package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +103 -0
  164. package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +288 -0
  165. package/plugin/vendor/reflexio/reflexio/lib/reflexio_lib.py +27 -0
  166. package/plugin/vendor/reflexio/reflexio/models/__init__.py +0 -0
  167. package/plugin/vendor/reflexio/reflexio/models/api_schema/__init__.py +0 -0
  168. package/plugin/vendor/reflexio/reflexio/models/api_schema/braintrust_schema.py +141 -0
  169. package/plugin/vendor/reflexio/reflexio/models/api_schema/common.py +41 -0
  170. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +3 -0
  171. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +1103 -0
  172. package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +63 -0
  173. package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +487 -0
  174. package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +28 -0
  175. package/plugin/vendor/reflexio/reflexio/models/api_schema/pending_tool_call_schema.py +83 -0
  176. package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +766 -0
  177. package/plugin/vendor/reflexio/reflexio/models/api_schema/service_schemas.py +9 -0
  178. package/plugin/vendor/reflexio/reflexio/models/api_schema/stall_state_schema.py +32 -0
  179. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/__init__.py +3 -0
  180. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +177 -0
  181. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +129 -0
  182. package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/enums.py +25 -0
  183. package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +280 -0
  184. package/plugin/vendor/reflexio/reflexio/models/config_schema.py +908 -0
  185. package/plugin/vendor/reflexio/reflexio/models/py.typed +0 -0
  186. package/plugin/vendor/reflexio/reflexio/server/OVERVIEW.md +90 -0
  187. package/plugin/vendor/reflexio/reflexio/server/README.md +616 -0
  188. package/plugin/vendor/reflexio/reflexio/server/__init__.py +210 -0
  189. package/plugin/vendor/reflexio/reflexio/server/__main__.py +132 -0
  190. package/plugin/vendor/reflexio/reflexio/server/_auth.py +25 -0
  191. package/plugin/vendor/reflexio/reflexio/server/api.py +2714 -0
  192. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/account_api.py +143 -0
  193. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/health_api.py +91 -0
  194. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/pending_tool_call_api.py +572 -0
  195. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/precondition_checks.py +66 -0
  196. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +540 -0
  197. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +50 -0
  198. package/plugin/vendor/reflexio/reflexio/server/api_endpoints/stall_state_api.py +100 -0
  199. package/plugin/vendor/reflexio/reflexio/server/cache/__init__.py +15 -0
  200. package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +208 -0
  201. package/plugin/vendor/reflexio/reflexio/server/correlation.py +46 -0
  202. package/plugin/vendor/reflexio/reflexio/server/llm/__init__.py +30 -0
  203. package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +110 -0
  204. package/plugin/vendor/reflexio/reflexio/server/llm/image_utils.py +55 -0
  205. package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1595 -0
  206. package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +112 -0
  207. package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +469 -0
  208. package/plugin/vendor/reflexio/reflexio/server/llm/providers/__init__.py +1 -0
  209. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +1122 -0
  210. package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_stream_parser.py +197 -0
  211. package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +210 -0
  212. package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +213 -0
  213. package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +255 -0
  214. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/__init__.py +6 -0
  215. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +177 -0
  216. package/plugin/vendor/reflexio/reflexio/server/llm/rerank/llm_reranker.py +148 -0
  217. package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +699 -0
  218. package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +179 -0
  219. package/plugin/vendor/reflexio/reflexio/server/prompt/__init__.py +0 -0
  220. package/plugin/vendor/reflexio/reflexio/server/prompt/_dispatchers.py +54 -0
  221. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/README.md +121 -0
  222. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation/v1.0.0.prompt.md +58 -0
  223. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/agent_success_evaluation_with_comparison/v1.0.0.prompt.md +76 -0
  224. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/answer_synthesis/v1.5.2.prompt.md +88 -0
  225. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/compress_session_for_query/v1.3.0.prompt.md +31 -0
  226. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +20 -0
  227. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.0.0.prompt.md +53 -0
  228. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.1.0.prompt.md +57 -0
  229. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.2.0.prompt.md +68 -0
  230. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.3.0.prompt.md +70 -0
  231. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.4.0.prompt.md +77 -0
  232. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.5.0.prompt.md +82 -0
  233. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/memory_reflection/v1.6.0.prompt.md +83 -0
  234. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.1.0.prompt.md +193 -0
  235. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_aggregation/v2.2.0.prompt.md +206 -0
  236. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0-deprecated.prompt.md +66 -0
  237. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.0.0.prompt.md +43 -0
  238. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v1.1.0.prompt.md +46 -0
  239. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0-deprecated.prompt.md +64 -0
  240. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.0.0.prompt.md +39 -0
  241. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.1.0.prompt.md +39 -0
  242. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.2.0.prompt.md +47 -0
  243. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +58 -0
  244. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.0.2.prompt.md +254 -0
  245. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.1.0.prompt.md +274 -0
  246. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +279 -0
  247. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v1.0.0.prompt.md +73 -0
  248. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v2.0.0.prompt.md +86 -0
  249. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.0.0.prompt.md +97 -0
  250. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.1.0.prompt.md +119 -0
  251. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.2.0.prompt.md +123 -0
  252. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +127 -0
  253. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.0.0.prompt.md +14 -0
  254. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.1.0.prompt.md +24 -0
  255. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main/v1.2.0.prompt.md +29 -0
  256. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.0.0.prompt.md +11 -0
  257. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.1.0.prompt.md +21 -0
  258. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_main_expert/v1.2.0.prompt.md +25 -0
  259. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.0.0.prompt.md +37 -0
  260. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.1.0.prompt.md +40 -0
  261. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_optimizer_judge/v1.2.0.prompt.md +36 -0
  262. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v1.0.0.prompt.md +45 -0
  263. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v2.0.0.prompt.md +81 -0
  264. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate/v3.0.0.prompt.md +80 -0
  265. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_should_generate_expert/v1.0.0.prompt.md +34 -0
  266. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_deduplication/v1.0.0.prompt.md +116 -0
  267. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate/v1.0.0.prompt.md +33 -0
  268. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_should_generate_override/v1.0.0.prompt.md +16 -0
  269. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.0.0.prompt.md +140 -0
  270. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_instruction_start/v1.1.0.prompt.md +160 -0
  271. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/profile_update_main/v1.0.0.prompt.md +14 -0
  272. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +19 -0
  273. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/rerank_relevance/v1.1.0.prompt.md +44 -0
  274. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +43 -0
  275. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_content_evaluation/v1.0.0.prompt.md +33 -0
  276. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/feedback_extraction_main_v1.jsonl +10 -0
  277. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_evaluation/prompt_evaluation_dataset/profile_update_main_v1.jsonl +10 -0
  278. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_manager.py +280 -0
  279. package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_schema.py +11 -0
  280. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +131 -0
  281. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_constants.py +60 -0
  282. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_service.py +228 -0
  283. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluation_utils.py +87 -0
  284. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/agent_success_evaluator.py +372 -0
  285. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/delayed_group_evaluator.py +156 -0
  286. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +340 -0
  287. package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +471 -0
  288. package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +1626 -0
  289. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/__init__.py +0 -0
  290. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_cron.py +196 -0
  291. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/_encryption.py +101 -0
  292. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/client.py +167 -0
  293. package/plugin/vendor/reflexio/reflexio/server/services/braintrust/service.py +281 -0
  294. package/plugin/vendor/reflexio/reflexio/server/services/configurator/base_configurator.py +179 -0
  295. package/plugin/vendor/reflexio/reflexio/server/services/configurator/config_storage.py +62 -0
  296. package/plugin/vendor/reflexio/reflexio/server/services/configurator/configurator.py +87 -0
  297. package/plugin/vendor/reflexio/reflexio/server/services/configurator/local_file_config_storage.py +187 -0
  298. package/plugin/vendor/reflexio/reflexio/server/services/configurator/test_config_storage.py +162 -0
  299. package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +112 -0
  300. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/__init__.py +0 -0
  301. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/distribution.py +33 -0
  302. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/eval_sampler.py +126 -0
  303. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/group_aggregation.py +192 -0
  304. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/hero_state.py +75 -0
  305. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/rule_attribution.py +97 -0
  306. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +515 -0
  307. package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/shadow_aggregation.py +90 -0
  308. package/plugin/vendor/reflexio/reflexio/server/services/extraction/__init__.py +0 -0
  309. package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +91 -0
  310. package/plugin/vendor/reflexio/reflexio/server/services/extraction/invariants.py +303 -0
  311. package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +25 -0
  312. package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +351 -0
  313. package/plugin/vendor/reflexio/reflexio/server/services/extraction/plan.py +138 -0
  314. package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +217 -0
  315. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +468 -0
  316. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +171 -0
  317. package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +777 -0
  318. package/plugin/vendor/reflexio/reflexio/server/services/extraction/tools.py +1125 -0
  319. package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +91 -0
  320. package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +251 -0
  321. package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +689 -0
  322. package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +835 -0
  323. package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +89 -0
  324. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_aggregator.py +1388 -0
  325. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +960 -0
  326. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_extractor.py +436 -0
  327. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_generation_service.py +808 -0
  328. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_constants.py +28 -0
  329. package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_service_utils.py +362 -0
  330. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/__init__.py +24 -0
  331. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/assistant_webhook.py +246 -0
  332. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/gepa_adapter.py +291 -0
  333. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/judge.py +97 -0
  334. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/models.py +96 -0
  335. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +645 -0
  336. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/rollout.py +35 -0
  337. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scenario_resolver.py +93 -0
  338. package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +174 -0
  339. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/__init__.py +26 -0
  340. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_document_expander.py +179 -0
  341. package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +297 -0
  342. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +741 -0
  343. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_extractor.py +462 -0
  344. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +734 -0
  345. package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service_utils.py +290 -0
  346. package/plugin/vendor/reflexio/reflexio/server/services/reflection/__init__.py +17 -0
  347. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_extractor.py +247 -0
  348. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +800 -0
  349. package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service_utils.py +146 -0
  350. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/__init__.py +0 -0
  351. package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +70 -0
  352. package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
  353. package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +671 -0
  354. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/__init__.py +1 -0
  355. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +184 -0
  356. package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/outcome.py +81 -0
  357. package/plugin/vendor/reflexio/reflexio/server/services/storage/constants.py +2 -0
  358. package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +11 -0
  359. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +154 -0
  360. package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +155 -0
  361. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +59 -0
  362. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +1253 -0
  363. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +1945 -0
  364. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +600 -0
  365. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_operations.py +346 -0
  366. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1378 -0
  367. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +747 -0
  368. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +263 -0
  369. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +193 -0
  370. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +166 -0
  371. package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_stall_state.py +217 -0
  372. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +153 -0
  373. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +372 -0
  374. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_base.py +71 -0
  375. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +235 -0
  376. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +170 -0
  377. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +677 -0
  378. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_profiles.py +250 -0
  379. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +154 -0
  380. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +130 -0
  381. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +93 -0
  382. package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_stall_state.py +76 -0
  383. package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +568 -0
  384. package/plugin/vendor/reflexio/reflexio/server/site_var/README.md +77 -0
  385. package/plugin/vendor/reflexio/reflexio/server/site_var/feature_flags.py +116 -0
  386. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_manager.py +263 -0
  387. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/feature_flags.json +13 -0
  388. package/plugin/vendor/reflexio/reflexio/server/site_var/site_var_sources/llm_model_setting.json +7 -0
  389. package/plugin/vendor/reflexio/reflexio/server/tracing.py +158 -0
  390. package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +113 -0
  391. package/plugin/vendor/reflexio/reflexio/server/uvicorn_logging.py +76 -0
  392. package/plugin/vendor/reflexio/reflexio/test_support/__init__.py +1 -0
  393. package/plugin/vendor/reflexio/reflexio/test_support/llm_fixtures.py +62 -0
  394. package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +242 -0
  395. package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +129 -0
  396. package/plugin/vendor/reflexio/reflexio/test_support/skip_decorators.py +43 -0
@@ -0,0 +1,572 @@
1
+ """HTTP endpoints for resolving pending tool calls."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import hmac
7
+ import logging
8
+ import time
9
+ from collections.abc import Callable
10
+ from datetime import UTC, datetime
11
+ from typing import Any
12
+
13
+ from fastapi import (
14
+ APIRouter,
15
+ BackgroundTasks,
16
+ Depends,
17
+ Header,
18
+ HTTPException,
19
+ Query,
20
+ Request,
21
+ )
22
+
23
+ from reflexio.models.api_schema.pending_tool_call_schema import (
24
+ MarkPendingToolCallNotApplicableRequest,
25
+ PendingToolCallListResponse,
26
+ PendingToolCallResponse,
27
+ ResolvePendingToolCallRequest,
28
+ UpdatePendingToolCallAnswerRequest,
29
+ )
30
+ from reflexio.server.api_endpoints.request_context import (
31
+ RequestContext,
32
+ get_request_context,
33
+ )
34
+ from reflexio.server.services.extraction.resumable_agent import (
35
+ pending_tool_calls_enabled,
36
+ )
37
+ from reflexio.server.services.extraction.resume_worker import ExtractionResumeWorker
38
+ from reflexio.server.services.storage.error import StorageError
39
+ from reflexio.server.services.storage.storage_base import (
40
+ BaseStorage,
41
+ PendingToolCallRecord,
42
+ PendingToolCallStatus,
43
+ not_applicable_tool_result,
44
+ )
45
+ from reflexio.server.usage_metrics import record_usage_event
46
+
47
+ router = APIRouter(prefix="/api/pending_tool_calls", tags=["pending_tool_calls"])
48
+ logger = logging.getLogger(__name__)
49
+
50
+ _UNSUPPORTED_DETAIL = (
51
+ "Pending tool calls are not supported by the configured storage backend"
52
+ )
53
+ _HMAC_TIMESTAMP_TOLERANCE_SECONDS = 300
54
+ _ASK_HUMAN_TOOL_NAME = "ask_human"
55
+
56
+
57
+ def _require_storage(ctx: RequestContext) -> BaseStorage:
58
+ storage = ctx.storage
59
+ if storage is None:
60
+ raise HTTPException(status_code=503, detail="Storage not configured")
61
+ return storage
62
+
63
+
64
+ def _require_org_record(
65
+ record: PendingToolCallRecord | None,
66
+ *,
67
+ org_id: str,
68
+ ) -> PendingToolCallRecord:
69
+ if record is None or record.org_id != org_id:
70
+ raise HTTPException(status_code=404, detail="Pending tool call not found")
71
+ return record
72
+
73
+
74
+ def _require_ask_human_record(record: PendingToolCallRecord) -> None:
75
+ if record.tool_name != _ASK_HUMAN_TOOL_NAME:
76
+ raise HTTPException(
77
+ status_code=409,
78
+ detail="Only ask_human tool calls can be managed from this endpoint",
79
+ )
80
+
81
+
82
+ def _reload_resolved_record_after_write_conflict(
83
+ *,
84
+ storage: BaseStorage,
85
+ pending_tool_call_id: str,
86
+ org_id: str,
87
+ desired_result: dict[str, Any],
88
+ different_result_detail: str,
89
+ ) -> PendingToolCallRecord:
90
+ latest = _run_with_pending_tool_call_migration_retry(
91
+ storage=storage,
92
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
93
+ )
94
+ latest = _require_org_record(latest, org_id=org_id)
95
+ if latest.status == PendingToolCallStatus.RESOLVED:
96
+ if latest.result == desired_result:
97
+ return latest
98
+ raise HTTPException(status_code=409, detail=different_result_detail)
99
+ raise HTTPException(
100
+ status_code=409,
101
+ detail=f"Pending tool call is {latest.status.value}",
102
+ )
103
+
104
+
105
+ def _drain_resumable_followups(ctx: RequestContext) -> None:
106
+ if not pending_tool_calls_enabled(ctx):
107
+ return
108
+ worker = ExtractionResumeWorker(request_context=ctx)
109
+ worker.drain()
110
+
111
+
112
+ def _is_missing_pending_tool_call_storage_error(exc: StorageError) -> bool:
113
+ message = exc.message if hasattr(exc, "message") else str(exc)
114
+ return "_pending_tool_calls" in message and (
115
+ "schema cache" in message or "does not exist" in message
116
+ )
117
+
118
+
119
+ def _run_with_pending_tool_call_migration_retry[T](
120
+ *,
121
+ storage: BaseStorage,
122
+ operation: Callable[[], T],
123
+ ) -> T:
124
+ try:
125
+ return operation()
126
+ except StorageError as exc:
127
+ if not _is_missing_pending_tool_call_storage_error(exc):
128
+ raise
129
+ migrate = getattr(storage, "migrate", None)
130
+ if not callable(migrate):
131
+ raise
132
+ logger.warning(
133
+ "event=pending_tool_call_storage_schema_missing action=migrate_and_retry"
134
+ )
135
+ migrate()
136
+ return operation()
137
+
138
+
139
+ def _verify_hmac_signature(
140
+ *,
141
+ body: bytes,
142
+ timestamp: str | None,
143
+ signature: str | None,
144
+ secrets: list[str],
145
+ ) -> None:
146
+ if not secrets:
147
+ return
148
+ if not timestamp or not signature:
149
+ raise HTTPException(status_code=401, detail="Missing HMAC signature")
150
+ try:
151
+ timestamp_value = int(timestamp)
152
+ except ValueError as exc:
153
+ raise HTTPException(status_code=401, detail="Invalid HMAC timestamp") from exc
154
+ if abs(time.time() - timestamp_value) > _HMAC_TIMESTAMP_TOLERANCE_SECONDS:
155
+ raise HTTPException(status_code=401, detail="Expired HMAC timestamp")
156
+
157
+ expected_prefix = "sha256="
158
+ provided = (
159
+ signature
160
+ if signature.startswith(expected_prefix)
161
+ else f"{expected_prefix}{signature}"
162
+ )
163
+ signed_payload = timestamp.encode("utf-8") + b"." + body
164
+ for secret in secrets:
165
+ digest = hmac.new(
166
+ secret.encode("utf-8"),
167
+ signed_payload,
168
+ hashlib.sha256,
169
+ ).hexdigest()
170
+ if hmac.compare_digest(provided, f"{expected_prefix}{digest}"):
171
+ return
172
+ raise HTTPException(status_code=401, detail="Invalid HMAC signature")
173
+
174
+
175
+ def _valid_for_seconds(
176
+ *,
177
+ payload_value: int | None,
178
+ record: PendingToolCallRecord,
179
+ ctx: RequestContext,
180
+ ) -> int:
181
+ pending_config = ctx.configurator.get_config().pending_tool_call_config
182
+ return (
183
+ payload_value
184
+ or pending_config.for_tool(record.tool_name).prior_answer_valid_seconds
185
+ )
186
+
187
+
188
+ @router.get("", response_model=PendingToolCallListResponse)
189
+ def list_pending_tool_calls(
190
+ status: PendingToolCallStatus | None = Query(default=None),
191
+ limit: int = Query(default=100, ge=1, le=500),
192
+ ctx: RequestContext = Depends(get_request_context),
193
+ ) -> PendingToolCallListResponse:
194
+ storage = _require_storage(ctx)
195
+ try:
196
+ records = _run_with_pending_tool_call_migration_retry(
197
+ storage=storage,
198
+ operation=lambda: storage.list_pending_tool_calls(
199
+ status=status,
200
+ limit=limit,
201
+ ),
202
+ )
203
+ except NotImplementedError as exc:
204
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
205
+ except StorageError as exc:
206
+ raise HTTPException(status_code=503, detail=exc.message) from exc
207
+ return PendingToolCallListResponse(
208
+ pending_tool_calls=[
209
+ PendingToolCallResponse.from_record(record)
210
+ for record in records
211
+ if record.org_id == ctx.org_id
212
+ ]
213
+ )
214
+
215
+
216
+ @router.get("/{pending_tool_call_id}", response_model=PendingToolCallResponse)
217
+ def get_pending_tool_call(
218
+ pending_tool_call_id: str,
219
+ ctx: RequestContext = Depends(get_request_context),
220
+ ) -> PendingToolCallResponse:
221
+ storage = _require_storage(ctx)
222
+ try:
223
+ record = _run_with_pending_tool_call_migration_retry(
224
+ storage=storage,
225
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
226
+ )
227
+ except NotImplementedError as exc:
228
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
229
+ except StorageError as exc:
230
+ raise HTTPException(status_code=503, detail=exc.message) from exc
231
+ return PendingToolCallResponse.from_record(
232
+ _require_org_record(record, org_id=ctx.org_id)
233
+ )
234
+
235
+
236
+ @router.post("/{pending_tool_call_id}/resolve", response_model=PendingToolCallResponse)
237
+ async def resolve_pending_tool_call(
238
+ pending_tool_call_id: str,
239
+ request: Request,
240
+ payload: ResolvePendingToolCallRequest,
241
+ background_tasks: BackgroundTasks,
242
+ x_reflexio_signature: str | None = Header(default=None),
243
+ x_reflexio_timestamp: str | None = Header(default=None),
244
+ ctx: RequestContext = Depends(get_request_context),
245
+ ) -> PendingToolCallResponse:
246
+ storage = _require_storage(ctx)
247
+ pending_config = ctx.configurator.get_config().pending_tool_call_config
248
+ _verify_hmac_signature(
249
+ body=await request.body(),
250
+ timestamp=x_reflexio_timestamp,
251
+ signature=x_reflexio_signature,
252
+ secrets=pending_config.hmac_secrets,
253
+ )
254
+ try:
255
+ existing = _run_with_pending_tool_call_migration_retry(
256
+ storage=storage,
257
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
258
+ )
259
+ except NotImplementedError as exc:
260
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
261
+ except StorageError as exc:
262
+ raise HTTPException(status_code=503, detail=exc.message) from exc
263
+ record = _require_org_record(existing, org_id=ctx.org_id)
264
+
265
+ if record.status == PendingToolCallStatus.RESOLVED:
266
+ if record.result == payload.result:
267
+ return PendingToolCallResponse.from_record(record)
268
+ raise HTTPException(
269
+ status_code=409,
270
+ detail="Pending tool call already resolved with a different result",
271
+ )
272
+ if record.status != PendingToolCallStatus.PENDING:
273
+ raise HTTPException(
274
+ status_code=409,
275
+ detail=f"Pending tool call is {record.status.value}",
276
+ )
277
+
278
+ valid_for_seconds = _valid_for_seconds(
279
+ payload_value=payload.valid_for_seconds,
280
+ record=record,
281
+ ctx=ctx,
282
+ )
283
+ try:
284
+ resolved = storage.resolve_pending_tool_call(
285
+ pending_tool_call_id,
286
+ result=payload.result,
287
+ resolved_at=datetime.now(UTC),
288
+ valid_for_seconds=valid_for_seconds,
289
+ )
290
+ except StorageError as exc:
291
+ raise HTTPException(status_code=503, detail=exc.message) from exc
292
+ if resolved is None:
293
+ latest = _run_with_pending_tool_call_migration_retry(
294
+ storage=storage,
295
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
296
+ )
297
+ latest = _require_org_record(latest, org_id=ctx.org_id)
298
+ if latest.status == PendingToolCallStatus.RESOLVED:
299
+ if latest.result == payload.result:
300
+ return PendingToolCallResponse.from_record(latest)
301
+ raise HTTPException(
302
+ status_code=409,
303
+ detail="Pending tool call already resolved with a different result",
304
+ )
305
+ raise HTTPException(
306
+ status_code=409,
307
+ detail=f"Pending tool call is {latest.status.value}",
308
+ )
309
+ if resolved.status != PendingToolCallStatus.RESOLVED:
310
+ raise HTTPException(
311
+ status_code=409,
312
+ detail=f"Pending tool call is {resolved.status.value}",
313
+ )
314
+ if resolved.result != payload.result:
315
+ raise HTTPException(
316
+ status_code=409,
317
+ detail="Pending tool call already resolved with a different result",
318
+ )
319
+ logger.info(
320
+ "event=pending_tool_call_resolved org_id=%s user_id=%s "
321
+ "pending_tool_call_id=%s tool_name=%s",
322
+ ctx.org_id,
323
+ record.user_id,
324
+ pending_tool_call_id,
325
+ record.tool_name,
326
+ )
327
+ record_usage_event(
328
+ org_id=ctx.org_id,
329
+ event_name="pending_tool_call_resolved",
330
+ event_category="extraction_agent",
331
+ user_id=record.user_id,
332
+ outcome="resolved",
333
+ metadata={
334
+ "pending_tool_call_id": pending_tool_call_id,
335
+ "tool_name": record.tool_name,
336
+ },
337
+ )
338
+ background_tasks.add_task(_drain_resumable_followups, ctx)
339
+ return PendingToolCallResponse.from_record(resolved)
340
+
341
+
342
+ @router.patch("/{pending_tool_call_id}/answer", response_model=PendingToolCallResponse)
343
+ async def update_pending_tool_call_answer(
344
+ pending_tool_call_id: str,
345
+ request: Request,
346
+ payload: UpdatePendingToolCallAnswerRequest,
347
+ background_tasks: BackgroundTasks,
348
+ x_reflexio_signature: str | None = Header(default=None),
349
+ x_reflexio_timestamp: str | None = Header(default=None),
350
+ ctx: RequestContext = Depends(get_request_context),
351
+ ) -> PendingToolCallResponse:
352
+ storage = _require_storage(ctx)
353
+ pending_config = ctx.configurator.get_config().pending_tool_call_config
354
+ _verify_hmac_signature(
355
+ body=await request.body(),
356
+ timestamp=x_reflexio_timestamp,
357
+ signature=x_reflexio_signature,
358
+ secrets=pending_config.hmac_secrets,
359
+ )
360
+ try:
361
+ existing = _run_with_pending_tool_call_migration_retry(
362
+ storage=storage,
363
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
364
+ )
365
+ except NotImplementedError as exc:
366
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
367
+ except StorageError as exc:
368
+ raise HTTPException(status_code=503, detail=exc.message) from exc
369
+ record = _require_org_record(existing, org_id=ctx.org_id)
370
+ _require_ask_human_record(record)
371
+
372
+ if record.status != PendingToolCallStatus.RESOLVED:
373
+ raise HTTPException(
374
+ status_code=409,
375
+ detail=f"Pending tool call is {record.status.value}",
376
+ )
377
+ answer = payload.answer.strip()
378
+ if not answer:
379
+ raise HTTPException(status_code=422, detail="Answer cannot be empty")
380
+ desired_result = {"answer": answer}
381
+
382
+ try:
383
+ updated = storage.update_resolved_pending_tool_call_result(
384
+ pending_tool_call_id,
385
+ result=desired_result,
386
+ resolved_at=datetime.now(UTC),
387
+ valid_for_seconds=_valid_for_seconds(
388
+ payload_value=payload.valid_for_seconds,
389
+ record=record,
390
+ ctx=ctx,
391
+ ),
392
+ )
393
+ except StorageError as exc:
394
+ raise HTTPException(status_code=503, detail=exc.message) from exc
395
+ if updated is None:
396
+ updated = _reload_resolved_record_after_write_conflict(
397
+ storage=storage,
398
+ pending_tool_call_id=pending_tool_call_id,
399
+ org_id=ctx.org_id,
400
+ desired_result=desired_result,
401
+ different_result_detail=(
402
+ "Pending tool call already resolved with a different result"
403
+ ),
404
+ )
405
+ updated = _require_org_record(updated, org_id=ctx.org_id)
406
+ if updated.status != PendingToolCallStatus.RESOLVED:
407
+ raise HTTPException(
408
+ status_code=409,
409
+ detail=f"Pending tool call is {updated.status.value}",
410
+ )
411
+ if updated.result != desired_result:
412
+ raise HTTPException(
413
+ status_code=409,
414
+ detail="Pending tool call already resolved with a different result",
415
+ )
416
+ logger.info(
417
+ "event=pending_tool_call_answer_updated org_id=%s user_id=%s "
418
+ "pending_tool_call_id=%s tool_name=%s",
419
+ ctx.org_id,
420
+ record.user_id,
421
+ pending_tool_call_id,
422
+ record.tool_name,
423
+ )
424
+ record_usage_event(
425
+ org_id=ctx.org_id,
426
+ event_name="pending_tool_call_answer_updated",
427
+ event_category="extraction_agent",
428
+ user_id=record.user_id,
429
+ outcome="updated",
430
+ metadata={
431
+ "pending_tool_call_id": pending_tool_call_id,
432
+ "tool_name": record.tool_name,
433
+ },
434
+ )
435
+ background_tasks.add_task(_drain_resumable_followups, ctx)
436
+ return PendingToolCallResponse.from_record(updated)
437
+
438
+
439
+ @router.post(
440
+ "/{pending_tool_call_id}/not_applicable",
441
+ response_model=PendingToolCallResponse,
442
+ )
443
+ async def mark_pending_tool_call_not_applicable(
444
+ pending_tool_call_id: str,
445
+ request: Request,
446
+ payload: MarkPendingToolCallNotApplicableRequest,
447
+ background_tasks: BackgroundTasks,
448
+ x_reflexio_signature: str | None = Header(default=None),
449
+ x_reflexio_timestamp: str | None = Header(default=None),
450
+ ctx: RequestContext = Depends(get_request_context),
451
+ ) -> PendingToolCallResponse:
452
+ storage = _require_storage(ctx)
453
+ pending_config = ctx.configurator.get_config().pending_tool_call_config
454
+ _verify_hmac_signature(
455
+ body=await request.body(),
456
+ timestamp=x_reflexio_timestamp,
457
+ signature=x_reflexio_signature,
458
+ secrets=pending_config.hmac_secrets,
459
+ )
460
+ try:
461
+ existing = _run_with_pending_tool_call_migration_retry(
462
+ storage=storage,
463
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
464
+ )
465
+ except NotImplementedError as exc:
466
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
467
+ except StorageError as exc:
468
+ raise HTTPException(status_code=503, detail=exc.message) from exc
469
+ record = _require_org_record(existing, org_id=ctx.org_id)
470
+ _require_ask_human_record(record)
471
+
472
+ if record.status not in (
473
+ PendingToolCallStatus.PENDING,
474
+ PendingToolCallStatus.RESOLVED,
475
+ ):
476
+ raise HTTPException(
477
+ status_code=409,
478
+ detail=f"Pending tool call is {record.status.value}",
479
+ )
480
+
481
+ try:
482
+ updated = storage.mark_pending_tool_call_not_applicable(
483
+ pending_tool_call_id,
484
+ resolved_at=datetime.now(UTC),
485
+ valid_for_seconds=_valid_for_seconds(
486
+ payload_value=payload.valid_for_seconds,
487
+ record=record,
488
+ ctx=ctx,
489
+ ),
490
+ )
491
+ except StorageError as exc:
492
+ raise HTTPException(status_code=503, detail=exc.message) from exc
493
+ desired_result = not_applicable_tool_result()
494
+ if updated is None:
495
+ updated = _reload_resolved_record_after_write_conflict(
496
+ storage=storage,
497
+ pending_tool_call_id=pending_tool_call_id,
498
+ org_id=ctx.org_id,
499
+ desired_result=desired_result,
500
+ different_result_detail=(
501
+ "Pending tool call could not be marked not applicable"
502
+ ),
503
+ )
504
+ updated = _require_org_record(updated, org_id=ctx.org_id)
505
+ if updated.status != PendingToolCallStatus.RESOLVED:
506
+ raise HTTPException(
507
+ status_code=409,
508
+ detail=f"Pending tool call is {updated.status.value}",
509
+ )
510
+ if updated.result != desired_result:
511
+ raise HTTPException(
512
+ status_code=409,
513
+ detail="Pending tool call could not be marked not applicable",
514
+ )
515
+ record_usage_event(
516
+ org_id=ctx.org_id,
517
+ event_name="pending_tool_call_marked_not_applicable",
518
+ event_category="extraction_agent",
519
+ user_id=record.user_id,
520
+ outcome="not_applicable",
521
+ metadata={
522
+ "pending_tool_call_id": pending_tool_call_id,
523
+ "tool_name": record.tool_name,
524
+ },
525
+ )
526
+ background_tasks.add_task(_drain_resumable_followups, ctx)
527
+ return PendingToolCallResponse.from_record(updated)
528
+
529
+
530
+ @router.post("/{pending_tool_call_id}/cancel", response_model=PendingToolCallResponse)
531
+ def cancel_pending_tool_call(
532
+ pending_tool_call_id: str,
533
+ ctx: RequestContext = Depends(get_request_context),
534
+ ) -> PendingToolCallResponse:
535
+ storage = _require_storage(ctx)
536
+ try:
537
+ existing = _run_with_pending_tool_call_migration_retry(
538
+ storage=storage,
539
+ operation=lambda: storage.get_pending_tool_call(pending_tool_call_id),
540
+ )
541
+ except NotImplementedError as exc:
542
+ raise HTTPException(status_code=503, detail=_UNSUPPORTED_DETAIL) from exc
543
+ except StorageError as exc:
544
+ raise HTTPException(status_code=503, detail=exc.message) from exc
545
+ record = _require_org_record(existing, org_id=ctx.org_id)
546
+
547
+ if record.status == PendingToolCallStatus.CANCELLED:
548
+ return PendingToolCallResponse.from_record(record)
549
+ if record.status != PendingToolCallStatus.PENDING:
550
+ raise HTTPException(
551
+ status_code=409,
552
+ detail=f"Pending tool call is {record.status.value}",
553
+ )
554
+
555
+ try:
556
+ cancelled = storage.cancel_pending_tool_call(pending_tool_call_id)
557
+ except StorageError as exc:
558
+ raise HTTPException(status_code=503, detail=exc.message) from exc
559
+ record_usage_event(
560
+ org_id=ctx.org_id,
561
+ event_name="pending_tool_call_cancelled",
562
+ event_category="extraction_agent",
563
+ user_id=record.user_id,
564
+ outcome="cancelled",
565
+ metadata={
566
+ "pending_tool_call_id": pending_tool_call_id,
567
+ "tool_name": record.tool_name,
568
+ },
569
+ )
570
+ return PendingToolCallResponse.from_record(
571
+ _require_org_record(cancelled, org_id=ctx.org_id)
572
+ )
@@ -0,0 +1,66 @@
1
+ from reflexio.models.api_schema.service_schemas import (
2
+ DeleteUserProfileRequest,
3
+ PublishUserInteractionRequest,
4
+ UserActionType,
5
+ )
6
+
7
+
8
+ def validate_publish_user_interaction_request(
9
+ request: PublishUserInteractionRequest,
10
+ ) -> tuple[bool, str]:
11
+ """
12
+ Validate the publish user interaction request
13
+
14
+ Args:
15
+ request (PublishUserInteractionRequest): The request to validate
16
+
17
+ Returns:
18
+ tuple[bool, str]: A tuple containing a boolean indicating if the request is valid and a message
19
+ """
20
+ if not request.interaction_data_list:
21
+ return False, "No interaction data provided"
22
+
23
+ for interaction_data in request.interaction_data_list:
24
+ if (
25
+ interaction_data.user_action != UserActionType.NONE
26
+ and not interaction_data.user_action_description
27
+ ):
28
+ return False, "User action description is required for user action"
29
+
30
+ if interaction_data.interacted_image_url and interaction_data.image_encoding:
31
+ return (
32
+ False,
33
+ "Image encoding and interacted image url cannot be provided together",
34
+ )
35
+
36
+ if (
37
+ not interaction_data.content
38
+ and not interaction_data.interacted_image_url
39
+ and not interaction_data.image_encoding
40
+ and not interaction_data.user_action
41
+ ):
42
+ return (
43
+ False,
44
+ "Text interaction, interacted image url, image encoding, and user action cannot be all empty",
45
+ )
46
+
47
+ return True, ""
48
+
49
+
50
+ def validate_delete_user_profile_request(
51
+ request: DeleteUserProfileRequest,
52
+ ) -> tuple[bool, str]:
53
+ """
54
+ Validate the delete user profile request
55
+
56
+ Args:
57
+ request (DeleteUserProfileRequest): The request to validate
58
+
59
+ Returns:
60
+ tuple[bool, str]: A tuple containing a boolean indicating if the request is valid and a message
61
+ """
62
+
63
+ if not request.profile_id and not request.search_query:
64
+ return False, "Profile id or search query is required"
65
+
66
+ return True, ""