activeagent 0.6.3 → 1.0.0.rc1

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 (282) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +210 -2
  3. data/README.md +15 -24
  4. data/lib/active_agent/base.rb +389 -39
  5. data/lib/active_agent/concerns/callbacks.rb +251 -0
  6. data/lib/active_agent/concerns/observers.rb +147 -0
  7. data/lib/active_agent/concerns/parameterized.rb +292 -0
  8. data/lib/active_agent/concerns/provider.rb +120 -0
  9. data/lib/active_agent/concerns/queueing.rb +36 -0
  10. data/lib/active_agent/concerns/rescue.rb +64 -0
  11. data/lib/active_agent/concerns/streaming.rb +282 -0
  12. data/lib/active_agent/concerns/tooling.rb +23 -0
  13. data/lib/active_agent/concerns/view.rb +150 -0
  14. data/lib/active_agent/configuration.rb +442 -20
  15. data/lib/active_agent/generation.rb +141 -47
  16. data/lib/active_agent/generation_provider/open_router/types.rb +505 -0
  17. data/lib/active_agent/generation_provider/xai_provider.rb +144 -0
  18. data/lib/active_agent/providers/_base_provider.rb +410 -0
  19. data/lib/active_agent/providers/anthropic/_types.rb +63 -0
  20. data/lib/active_agent/providers/anthropic/options.rb +53 -0
  21. data/lib/active_agent/providers/anthropic/request.rb +109 -0
  22. data/lib/active_agent/providers/anthropic/requests/_types.rb +190 -0
  23. data/lib/active_agent/providers/anthropic/requests/container_params.rb +19 -0
  24. data/lib/active_agent/providers/anthropic/requests/content/base.rb +21 -0
  25. data/lib/active_agent/providers/anthropic/requests/content/sources/base.rb +22 -0
  26. data/lib/active_agent/providers/anthropic/requests/context_management_config.rb +18 -0
  27. data/lib/active_agent/providers/anthropic/requests/messages/_types.rb +189 -0
  28. data/lib/active_agent/providers/anthropic/requests/messages/assistant.rb +23 -0
  29. data/lib/active_agent/providers/anthropic/requests/messages/base.rb +63 -0
  30. data/lib/active_agent/providers/anthropic/requests/messages/content/_types.rb +143 -0
  31. data/lib/active_agent/providers/anthropic/requests/messages/content/base.rb +21 -0
  32. data/lib/active_agent/providers/anthropic/requests/messages/content/document.rb +26 -0
  33. data/lib/active_agent/providers/anthropic/requests/messages/content/image.rb +23 -0
  34. data/lib/active_agent/providers/anthropic/requests/messages/content/redacted_thinking.rb +21 -0
  35. data/lib/active_agent/providers/anthropic/requests/messages/content/search_result.rb +27 -0
  36. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/_types.rb +171 -0
  37. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/base.rb +22 -0
  38. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_base64.rb +25 -0
  39. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_file.rb +23 -0
  40. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_text.rb +25 -0
  41. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_url.rb +23 -0
  42. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_base64.rb +27 -0
  43. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_file.rb +23 -0
  44. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_url.rb +23 -0
  45. data/lib/active_agent/providers/anthropic/requests/messages/content/text.rb +22 -0
  46. data/lib/active_agent/providers/anthropic/requests/messages/content/thinking.rb +23 -0
  47. data/lib/active_agent/providers/anthropic/requests/messages/content/tool_result.rb +24 -0
  48. data/lib/active_agent/providers/anthropic/requests/messages/content/tool_use.rb +28 -0
  49. data/lib/active_agent/providers/anthropic/requests/messages/user.rb +21 -0
  50. data/lib/active_agent/providers/anthropic/requests/metadata.rb +18 -0
  51. data/lib/active_agent/providers/anthropic/requests/response_format.rb +22 -0
  52. data/lib/active_agent/providers/anthropic/requests/thinking_config/_types.rb +60 -0
  53. data/lib/active_agent/providers/anthropic/requests/thinking_config/base.rb +20 -0
  54. data/lib/active_agent/providers/anthropic/requests/thinking_config/disabled.rb +16 -0
  55. data/lib/active_agent/providers/anthropic/requests/thinking_config/enabled.rb +20 -0
  56. data/lib/active_agent/providers/anthropic/requests/tool_choice/_types.rb +78 -0
  57. data/lib/active_agent/providers/anthropic/requests/tool_choice/any.rb +17 -0
  58. data/lib/active_agent/providers/anthropic/requests/tool_choice/auto.rb +17 -0
  59. data/lib/active_agent/providers/anthropic/requests/tool_choice/base.rb +20 -0
  60. data/lib/active_agent/providers/anthropic/requests/tool_choice/none.rb +16 -0
  61. data/lib/active_agent/providers/anthropic/requests/tool_choice/tool.rb +20 -0
  62. data/lib/active_agent/providers/anthropic_provider.rb +211 -0
  63. data/lib/active_agent/providers/common/messages/_types.rb +124 -0
  64. data/lib/active_agent/providers/common/messages/assistant.rb +57 -0
  65. data/lib/active_agent/providers/common/messages/base.rb +17 -0
  66. data/lib/active_agent/providers/common/messages/system.rb +20 -0
  67. data/lib/active_agent/providers/common/messages/tool.rb +21 -0
  68. data/lib/active_agent/providers/common/messages/user.rb +20 -0
  69. data/lib/active_agent/providers/common/model.rb +361 -0
  70. data/lib/active_agent/providers/common/response.rb +13 -0
  71. data/lib/active_agent/providers/common/responses/_types.rb +51 -0
  72. data/lib/active_agent/providers/common/responses/base.rb +151 -0
  73. data/lib/active_agent/providers/common/responses/embed.rb +33 -0
  74. data/lib/active_agent/providers/common/responses/format.rb +31 -0
  75. data/lib/active_agent/providers/common/responses/message.rb +3 -0
  76. data/lib/active_agent/providers/common/responses/prompt.rb +42 -0
  77. data/lib/active_agent/providers/concerns/exception_handler.rb +72 -0
  78. data/lib/active_agent/providers/concerns/previewable.rb +150 -0
  79. data/lib/active_agent/providers/log_subscriber.rb +360 -0
  80. data/lib/active_agent/providers/mock/_types.rb +77 -0
  81. data/lib/active_agent/providers/mock/embedding_request.rb +17 -0
  82. data/lib/active_agent/providers/mock/messages/_types.rb +103 -0
  83. data/lib/active_agent/providers/mock/messages/assistant.rb +26 -0
  84. data/lib/active_agent/providers/mock/messages/base.rb +63 -0
  85. data/lib/active_agent/providers/mock/messages/user.rb +18 -0
  86. data/lib/active_agent/providers/mock/options.rb +30 -0
  87. data/lib/active_agent/providers/mock/request.rb +38 -0
  88. data/lib/active_agent/providers/mock_provider.rb +311 -0
  89. data/lib/active_agent/providers/ollama/_types.rb +5 -0
  90. data/lib/active_agent/providers/ollama/chat/_types.rb +44 -0
  91. data/lib/active_agent/providers/ollama/chat/request.rb +70 -0
  92. data/lib/active_agent/providers/ollama/chat/requests/_types.rb +3 -0
  93. data/lib/active_agent/providers/ollama/chat/requests/messages/_types.rb +116 -0
  94. data/lib/active_agent/providers/ollama/chat/requests/messages/assistant.rb +19 -0
  95. data/lib/active_agent/providers/ollama/chat/requests/messages/user.rb +19 -0
  96. data/lib/active_agent/providers/ollama/embedding/_types.rb +44 -0
  97. data/lib/active_agent/providers/ollama/embedding/request.rb +77 -0
  98. data/lib/active_agent/providers/ollama/embedding/requests/_types.rb +83 -0
  99. data/lib/active_agent/providers/ollama/embedding/requests/options.rb +104 -0
  100. data/lib/active_agent/providers/ollama/options.rb +27 -0
  101. data/lib/active_agent/providers/ollama_provider.rb +95 -0
  102. data/lib/active_agent/providers/open_ai/_base.rb +58 -0
  103. data/lib/active_agent/providers/open_ai/_types.rb +5 -0
  104. data/lib/active_agent/providers/open_ai/chat/_types.rb +44 -0
  105. data/lib/active_agent/providers/open_ai/chat/request.rb +215 -0
  106. data/lib/active_agent/providers/open_ai/chat/requests/_types.rb +229 -0
  107. data/lib/active_agent/providers/open_ai/chat/requests/audio.rb +24 -0
  108. data/lib/active_agent/providers/open_ai/chat/requests/messages/_types.rb +123 -0
  109. data/lib/active_agent/providers/open_ai/chat/requests/messages/assistant.rb +42 -0
  110. data/lib/active_agent/providers/open_ai/chat/requests/messages/base.rb +78 -0
  111. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/_types.rb +133 -0
  112. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/audio.rb +35 -0
  113. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/base.rb +24 -0
  114. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/file.rb +26 -0
  115. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/_types.rb +60 -0
  116. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/details.rb +41 -0
  117. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/image.rb +37 -0
  118. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/refusal.rb +25 -0
  119. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/text.rb +25 -0
  120. data/lib/active_agent/providers/open_ai/chat/requests/messages/developer.rb +25 -0
  121. data/lib/active_agent/providers/open_ai/chat/requests/messages/function.rb +25 -0
  122. data/lib/active_agent/providers/open_ai/chat/requests/messages/system.rb +25 -0
  123. data/lib/active_agent/providers/open_ai/chat/requests/messages/tool.rb +26 -0
  124. data/lib/active_agent/providers/open_ai/chat/requests/messages/user.rb +32 -0
  125. data/lib/active_agent/providers/open_ai/chat/requests/prediction.rb +46 -0
  126. data/lib/active_agent/providers/open_ai/chat/requests/response_format.rb +53 -0
  127. data/lib/active_agent/providers/open_ai/chat/requests/stream_options.rb +24 -0
  128. data/lib/active_agent/providers/open_ai/chat/requests/tool_choice.rb +26 -0
  129. data/lib/active_agent/providers/open_ai/chat/requests/tools/_types.rb +5 -0
  130. data/lib/active_agent/providers/open_ai/chat/requests/tools/base.rb +22 -0
  131. data/lib/active_agent/providers/open_ai/chat/requests/tools/custom_tool.rb +41 -0
  132. data/lib/active_agent/providers/open_ai/chat/requests/tools/function_tool.rb +51 -0
  133. data/lib/active_agent/providers/open_ai/chat/requests/web_search_options.rb +45 -0
  134. data/lib/active_agent/providers/open_ai/chat_provider.rb +198 -0
  135. data/lib/active_agent/providers/open_ai/embedding/_types.rb +45 -0
  136. data/lib/active_agent/providers/open_ai/embedding/request.rb +85 -0
  137. data/lib/active_agent/providers/open_ai/embedding/requests/_types.rb +49 -0
  138. data/lib/active_agent/providers/open_ai/options.rb +74 -0
  139. data/lib/active_agent/providers/open_ai/responses/_types.rb +50 -0
  140. data/lib/active_agent/providers/open_ai/responses/request.rb +163 -0
  141. data/lib/active_agent/providers/open_ai/responses/requests/_types.rb +231 -0
  142. data/lib/active_agent/providers/open_ai/responses/requests/conversation.rb +23 -0
  143. data/lib/active_agent/providers/open_ai/responses/requests/inputs/_types.rb +264 -0
  144. data/lib/active_agent/providers/open_ai/responses/requests/inputs/assistant_message.rb +22 -0
  145. data/lib/active_agent/providers/open_ai/responses/requests/inputs/base.rb +89 -0
  146. data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb +30 -0
  147. data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call.rb +28 -0
  148. data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb +33 -0
  149. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/_types.rb +207 -0
  150. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/base.rb +22 -0
  151. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_audio.rb +26 -0
  152. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_file.rb +28 -0
  153. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_image.rb +28 -0
  154. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_text.rb +25 -0
  155. data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call.rb +28 -0
  156. data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call_output.rb +27 -0
  157. data/lib/active_agent/providers/open_ai/responses/requests/inputs/developer_message.rb +20 -0
  158. data/lib/active_agent/providers/open_ai/responses/requests/inputs/file_search_tool_call.rb +25 -0
  159. data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_call_output.rb +32 -0
  160. data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_tool_call.rb +28 -0
  161. data/lib/active_agent/providers/open_ai/responses/requests/inputs/image_gen_tool_call.rb +27 -0
  162. data/lib/active_agent/providers/open_ai/responses/requests/inputs/input_message.rb +31 -0
  163. data/lib/active_agent/providers/open_ai/responses/requests/inputs/item_reference.rb +23 -0
  164. data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call.rb +26 -0
  165. data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call_output.rb +33 -0
  166. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_request.rb +30 -0
  167. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_response.rb +28 -0
  168. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_list_tools.rb +29 -0
  169. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_tool_call.rb +35 -0
  170. data/lib/active_agent/providers/open_ai/responses/requests/inputs/output_message.rb +35 -0
  171. data/lib/active_agent/providers/open_ai/responses/requests/inputs/reasoning.rb +33 -0
  172. data/lib/active_agent/providers/open_ai/responses/requests/inputs/system_message.rb +20 -0
  173. data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_call_base.rb +27 -0
  174. data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_message.rb +23 -0
  175. data/lib/active_agent/providers/open_ai/responses/requests/inputs/user_message.rb +20 -0
  176. data/lib/active_agent/providers/open_ai/responses/requests/inputs/web_search_tool_call.rb +24 -0
  177. data/lib/active_agent/providers/open_ai/responses/requests/prompt_reference.rb +23 -0
  178. data/lib/active_agent/providers/open_ai/responses/requests/reasoning.rb +23 -0
  179. data/lib/active_agent/providers/open_ai/responses/requests/stream_options.rb +20 -0
  180. data/lib/active_agent/providers/open_ai/responses/requests/text/_types.rb +89 -0
  181. data/lib/active_agent/providers/open_ai/responses/requests/text/base.rb +22 -0
  182. data/lib/active_agent/providers/open_ai/responses/requests/text/json_object.rb +20 -0
  183. data/lib/active_agent/providers/open_ai/responses/requests/text/json_schema.rb +48 -0
  184. data/lib/active_agent/providers/open_ai/responses/requests/text/plain.rb +20 -0
  185. data/lib/active_agent/providers/open_ai/responses/requests/text.rb +41 -0
  186. data/lib/active_agent/providers/open_ai/responses/requests/tool_choice.rb +26 -0
  187. data/lib/active_agent/providers/open_ai/responses/requests/tools/_types.rb +112 -0
  188. data/lib/active_agent/providers/open_ai/responses/requests/tools/base.rb +25 -0
  189. data/lib/active_agent/providers/open_ai/responses/requests/tools/code_interpreter_tool.rb +23 -0
  190. data/lib/active_agent/providers/open_ai/responses/requests/tools/computer_tool.rb +27 -0
  191. data/lib/active_agent/providers/open_ai/responses/requests/tools/custom_tool.rb +28 -0
  192. data/lib/active_agent/providers/open_ai/responses/requests/tools/file_search_tool.rb +27 -0
  193. data/lib/active_agent/providers/open_ai/responses/requests/tools/function_tool.rb +29 -0
  194. data/lib/active_agent/providers/open_ai/responses/requests/tools/image_generation_tool.rb +37 -0
  195. data/lib/active_agent/providers/open_ai/responses/requests/tools/local_shell_tool.rb +21 -0
  196. data/lib/active_agent/providers/open_ai/responses/requests/tools/mcp_tool.rb +41 -0
  197. data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_preview_tool.rb +24 -0
  198. data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_tool.rb +25 -0
  199. data/lib/active_agent/providers/open_ai/responses_provider.rb +153 -0
  200. data/lib/active_agent/providers/open_ai/schema.yml +65937 -0
  201. data/lib/active_agent/providers/open_ai_provider.rb +97 -0
  202. data/lib/active_agent/providers/open_router/_types.rb +45 -0
  203. data/lib/active_agent/providers/open_router/options.rb +93 -0
  204. data/lib/active_agent/providers/open_router/request.rb +83 -0
  205. data/lib/active_agent/providers/open_router/requests/_types.rb +198 -0
  206. data/lib/active_agent/providers/open_router/requests/message.rb +1 -0
  207. data/lib/active_agent/providers/open_router/requests/messages/_types.rb +59 -0
  208. data/lib/active_agent/providers/open_router/requests/messages/assistant.rb +20 -0
  209. data/lib/active_agent/providers/open_router/requests/messages/content/_types.rb +97 -0
  210. data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +27 -0
  211. data/lib/active_agent/providers/open_router/requests/messages/content/files/_types.rb +61 -0
  212. data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +26 -0
  213. data/lib/active_agent/providers/open_router/requests/messages/user.rb +30 -0
  214. data/lib/active_agent/providers/open_router/requests/plugin.rb +25 -0
  215. data/lib/active_agent/providers/open_router/requests/plugins/_types.rb +46 -0
  216. data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +29 -0
  217. data/lib/active_agent/providers/open_router/requests/prediction.rb +17 -0
  218. data/lib/active_agent/providers/open_router/requests/provider_preferences/_types.rb +44 -0
  219. data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +30 -0
  220. data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +64 -0
  221. data/lib/active_agent/providers/open_router/requests/response_format.rb +49 -0
  222. data/lib/active_agent/providers/open_router_provider.rb +53 -0
  223. data/lib/active_agent/providers/openai_provider.rb +2 -0
  224. data/lib/active_agent/providers/openrouter_provider.rb +2 -0
  225. data/lib/active_agent/railtie.rb +8 -6
  226. data/lib/active_agent/schema_generator.rb +333 -166
  227. data/lib/active_agent/version.rb +1 -1
  228. data/lib/active_agent.rb +112 -36
  229. data/lib/generators/active_agent/agent/USAGE +78 -0
  230. data/lib/generators/active_agent/{agent_generator.rb → agent/agent_generator.rb} +14 -4
  231. data/lib/generators/active_agent/install/USAGE +25 -0
  232. data/lib/generators/active_agent/{install_generator.rb → install/install_generator.rb} +1 -19
  233. data/lib/generators/active_agent/templates/agent.rb.tt +7 -3
  234. data/lib/generators/active_agent/templates/application_agent.rb.tt +0 -2
  235. data/lib/generators/erb/agent_generator.rb +31 -16
  236. data/lib/generators/erb/templates/instructions.md.erb.tt +3 -0
  237. data/lib/generators/erb/templates/instructions.md.tt +3 -0
  238. data/lib/generators/erb/templates/instructions.text.tt +1 -0
  239. data/lib/generators/erb/templates/message.md.erb.tt +5 -0
  240. data/lib/generators/erb/templates/schema.json.tt +10 -0
  241. data/lib/generators/test_unit/agent_generator.rb +1 -1
  242. data/lib/generators/test_unit/templates/functional_test.rb.tt +4 -2
  243. metadata +320 -65
  244. data/lib/active_agent/action_prompt/action.rb +0 -13
  245. data/lib/active_agent/action_prompt/base.rb +0 -623
  246. data/lib/active_agent/action_prompt/message.rb +0 -126
  247. data/lib/active_agent/action_prompt/prompt.rb +0 -136
  248. data/lib/active_agent/action_prompt.rb +0 -19
  249. data/lib/active_agent/callbacks.rb +0 -33
  250. data/lib/active_agent/generation_provider/anthropic_provider.rb +0 -163
  251. data/lib/active_agent/generation_provider/base.rb +0 -55
  252. data/lib/active_agent/generation_provider/base_adapter.rb +0 -19
  253. data/lib/active_agent/generation_provider/error_handling.rb +0 -167
  254. data/lib/active_agent/generation_provider/log_subscriber.rb +0 -92
  255. data/lib/active_agent/generation_provider/message_formatting.rb +0 -107
  256. data/lib/active_agent/generation_provider/ollama_provider.rb +0 -66
  257. data/lib/active_agent/generation_provider/open_ai_provider.rb +0 -279
  258. data/lib/active_agent/generation_provider/open_router_provider.rb +0 -385
  259. data/lib/active_agent/generation_provider/parameter_builder.rb +0 -119
  260. data/lib/active_agent/generation_provider/response.rb +0 -75
  261. data/lib/active_agent/generation_provider/responses_adapter.rb +0 -44
  262. data/lib/active_agent/generation_provider/stream_processing.rb +0 -58
  263. data/lib/active_agent/generation_provider/tool_management.rb +0 -142
  264. data/lib/active_agent/generation_provider.rb +0 -67
  265. data/lib/active_agent/log_subscriber.rb +0 -44
  266. data/lib/active_agent/parameterized.rb +0 -75
  267. data/lib/active_agent/prompt_helper.rb +0 -19
  268. data/lib/active_agent/queued_generation.rb +0 -12
  269. data/lib/active_agent/rescuable.rb +0 -34
  270. data/lib/active_agent/sanitizers.rb +0 -40
  271. data/lib/active_agent/streaming.rb +0 -34
  272. data/lib/active_agent/test_case.rb +0 -125
  273. data/lib/generators/USAGE +0 -47
  274. data/lib/generators/active_agent/USAGE +0 -56
  275. data/lib/generators/erb/install_generator.rb +0 -44
  276. data/lib/generators/erb/templates/layout.html.erb.tt +0 -1
  277. data/lib/generators/erb/templates/layout.json.erb.tt +0 -1
  278. data/lib/generators/erb/templates/layout.text.erb.tt +0 -1
  279. data/lib/generators/erb/templates/view.html.erb.tt +0 -5
  280. data/lib/generators/erb/templates/view.json.erb.tt +0 -16
  281. /data/lib/active_agent/{preview.rb → concerns/preview.rb} +0 -0
  282. /data/lib/generators/erb/templates/{view.text.erb.tt → message.text.erb.tt} +0 -0
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides observer and interceptor functionality for monitoring and modifying
5
+ # the prompt generation lifecycle.
6
+ #
7
+ # Observers are notified when prompts are generated and can react to events
8
+ # without modifying the prompt itself. Common use cases include logging,
9
+ # analytics, auditing, and notifications.
10
+ #
11
+ # Interceptors are called before prompts are sent to AI providers and can
12
+ # modify or prevent the prompt from being sent. Common use cases include
13
+ # content filtering, prompt modification, access control, and rate limiting.
14
+ module Observers
15
+ extend ActiveSupport::Concern
16
+
17
+ module ClassMethods
18
+ # Register one or more Observers which will be notified when prompt is generated.
19
+ #
20
+ # @param observers [Array<Class, String, Symbol>] Observer classes or names to register
21
+ # @return [void]
22
+ #
23
+ # @example Register multiple observers
24
+ # MyAgent.register_observers(PromptLogger, :analytics_tracker)
25
+ def register_observers(*observers)
26
+ observers.flatten.compact.each { |observer| register_observer(observer) }
27
+ end
28
+
29
+ # Unregister one or more previously registered Observers.
30
+ #
31
+ # @param observers [Array<Class, String, Symbol>] Observer classes or names to unregister
32
+ # @return [void]
33
+ #
34
+ # @example Unregister multiple observers
35
+ # MyAgent.unregister_observers(PromptLogger, :analytics_tracker)
36
+ def unregister_observers(*observers)
37
+ observers.flatten.compact.each { |observer| unregister_observer(observer) }
38
+ end
39
+
40
+ # Register one or more Interceptors which will be called before prompt is sent.
41
+ #
42
+ # @param interceptors [Array<Class, String, Symbol>] Interceptor classes or names to register
43
+ # @return [void]
44
+ #
45
+ # @example Register multiple interceptors
46
+ # MyAgent.register_interceptors(ContentFilter, :rate_limiter)
47
+ def register_interceptors(*interceptors)
48
+ interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
49
+ end
50
+
51
+ # Unregister one or more previously registered Interceptors.
52
+ #
53
+ # @param interceptors [Array<Class, String, Symbol>] Interceptor classes or names to unregister
54
+ # @return [void]
55
+ #
56
+ # @example Unregister multiple interceptors
57
+ # MyAgent.unregister_interceptors(ContentFilter, :rate_limiter)
58
+ def unregister_interceptors(*interceptors)
59
+ interceptors.flatten.compact.each { |interceptor| unregister_interceptor(interceptor) }
60
+ end
61
+
62
+ # Register an Observer which will be notified when prompt is generated.
63
+ #
64
+ # Either a class, string, or symbol can be passed in as the Observer.
65
+ # If a string or symbol is passed in it will be camelized and constantized.
66
+ #
67
+ # @param observer [Class, String, Symbol] The observer to register
68
+ # @return [void]
69
+ #
70
+ # @example Register with class
71
+ # MyAgent.register_observer(PromptLogger)
72
+ #
73
+ # @example Register with string
74
+ # MyAgent.register_observer("PromptLogger")
75
+ #
76
+ # @example Register with symbol
77
+ # MyAgent.register_observer(:prompt_logger)
78
+ def register_observer(observer)
79
+ Prompt.register_observer(observer_class_for(observer))
80
+ end
81
+
82
+ # Unregister a previously registered Observer.
83
+ #
84
+ # Either a class, string, or symbol can be passed in as the Observer.
85
+ # If a string or symbol is passed in it will be camelized and constantized.
86
+ #
87
+ # @param observer [Class, String, Symbol] The observer to unregister
88
+ # @return [void]
89
+ #
90
+ # @example Unregister with class
91
+ # MyAgent.unregister_observer(PromptLogger)
92
+ def unregister_observer(observer)
93
+ Prompt.unregister_observer(observer_class_for(observer))
94
+ end
95
+
96
+ # Register an Interceptor which will be called before prompt is sent.
97
+ #
98
+ # Either a class, string, or symbol can be passed in as the Interceptor.
99
+ # If a string or symbol is passed in it will be camelized and constantized.
100
+ #
101
+ # @param interceptor [Class, String, Symbol] The interceptor to register
102
+ # @return [void]
103
+ #
104
+ # @example Register with class
105
+ # MyAgent.register_interceptor(ContentFilter)
106
+ #
107
+ # @example Register with string
108
+ # MyAgent.register_interceptor("ContentFilter")
109
+ #
110
+ # @example Register with symbol
111
+ # MyAgent.register_interceptor(:content_filter)
112
+ def register_interceptor(interceptor)
113
+ Prompt.register_interceptor(observer_class_for(interceptor))
114
+ end
115
+
116
+ # Unregister a previously registered Interceptor.
117
+ #
118
+ # Either a class, string, or symbol can be passed in as the Interceptor.
119
+ # If a string or symbol is passed in it will be camelized and constantized.
120
+ #
121
+ # @param interceptor [Class, String, Symbol] The interceptor to unregister
122
+ # @return [void]
123
+ #
124
+ # @example Unregister with class
125
+ # MyAgent.unregister_interceptor(ContentFilter)
126
+ def unregister_interceptor(interceptor)
127
+ Prompt.unregister_interceptor(observer_class_for(interceptor))
128
+ end
129
+
130
+ private
131
+
132
+ # Converts observer/interceptor value to class.
133
+ #
134
+ # @param value [Class, String, Symbol] The observer/interceptor identifier
135
+ # @return [Class] The observer/interceptor class
136
+ # @api private
137
+ def observer_class_for(value) # :nodoc:
138
+ case value
139
+ when String, Symbol
140
+ value.to_s.camelize.constantize
141
+ else
142
+ value
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,292 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides parameterization support for agents, allowing you to pass variables
5
+ # to agent actions that can be used in templates.
6
+ #
7
+ # When included in an agent class, this concern enables the ability to pass
8
+ # parameters when calling agent actions, making agents reusable with different
9
+ # data contexts.
10
+ #
11
+ # @example Basic usage
12
+ # class WelcomeAgent < ActiveAgent::Base
13
+ # def greet
14
+ # # Template can access params[:user_name]
15
+ # end
16
+ # end
17
+ #
18
+ # # Pass parameters to the agent action
19
+ # WelcomeAgent.with(user_name: "Alice").greet.generate
20
+ #
21
+ # @example Using in templates
22
+ # # In greet.txt.erb template:
23
+ # # Hello <%= params[:user_name] %>!
24
+ #
25
+ # @example Multiple parameters
26
+ # OrderAgent.with(order_id: 123, customer: "John").process_order.generate
27
+ #
28
+ module Parameterized
29
+ extend ActiveSupport::Concern
30
+
31
+ included do
32
+ attr_writer :params
33
+
34
+ # Returns the parameters hash for this agent instance.
35
+ #
36
+ # @return [Hash] the parameters hash, defaults to empty hash if not set
37
+ def params
38
+ @params ||= {}
39
+ end
40
+ end
41
+
42
+ class_methods do
43
+ # Creates a parameterized agent proxy that will pass the given parameters
44
+ # to the agent instance when an action is called.
45
+ #
46
+ # @param params [Hash] the parameters to pass to the agent instance
47
+ # @return [ActiveAgent::Parameterized::Agent] a proxy object
48
+ # that will create parameterized generations when actions are called
49
+ #
50
+ # @example
51
+ # UserAgent.with(user_id: 123).send_notification.generate
52
+ #
53
+ def with(params = {})
54
+ ActiveAgent::Parameterized::Agent.new(self, params)
55
+ end
56
+ alias_method :prompt_with, :with
57
+
58
+ # Creates a direct prompt generation without defining an action method.
59
+ #
60
+ # This allows you to generate prompts inline without needing to define
61
+ # an action method on the agent class.
62
+ #
63
+ # @param messages [Array] message strings or hashes to add to conversation
64
+ # @param options [Hash] parameters to merge into prompt context
65
+ # @return [ActiveAgent::Parameterized::Generation] a generation instance
66
+ # ready for generate_now, generate_later, etc.
67
+ #
68
+ # @example Direct prompt generation
69
+ # MyAgent.prompt(message: "Hello world").generate_now
70
+ #
71
+ # @example With multiple messages
72
+ # MyAgent.prompt(messages: ["First", "Second"]).generate_now
73
+ #
74
+ # @example With options
75
+ # MyAgent.prompt(message: "Hello", temperature: 0.8).generate_now
76
+ def prompt(*messages, **options)
77
+ ActiveAgent::Parameterized::DirectGeneration.new(self, :prompt, {}, *messages, **options)
78
+ end
79
+
80
+ # Creates a direct embed generation without defining an action method.
81
+ #
82
+ # This allows you to generate embeddings inline without needing to define
83
+ # an action method on the agent class.
84
+ #
85
+ # @param input [String, Array<String>, nil] text to embed
86
+ # @param options [Hash] parameters to merge into embedding context
87
+ # @return [ActiveAgent::Parameterized::Generation] a generation instance
88
+ # ready for embed_now, embed_later, etc.
89
+ #
90
+ # @example Direct embedding
91
+ # MyAgent.embed(input: "Text to embed").embed_now
92
+ #
93
+ # @example With array input
94
+ # MyAgent.embed(input: ["First", "Second"]).embed_now
95
+ #
96
+ # @example With options
97
+ # MyAgent.embed(input: "Text", model: "text-embedding-3-large").embed_now
98
+ def embed(input = nil, **options)
99
+ ActiveAgent::Parameterized::DirectGeneration.new(self, :embed, {}, input, **options)
100
+ end
101
+ end
102
+
103
+ # Proxy class that intercepts method calls to create parameterized generations.
104
+ #
105
+ # This class is returned by {ClassMethods#with} and acts as a proxy to the
106
+ # actual agent class, capturing method calls to actions and creating
107
+ # {Generation} instances with the stored parameters.
108
+ #
109
+ # @api private
110
+ class Agent
111
+ # @param agent [Class] the agent class to proxy
112
+ # @param params [Hash] the parameters to pass to agent instances
113
+ def initialize(agent, params)
114
+ @agent = agent
115
+ @params = params
116
+ end
117
+
118
+ # Intercepts calls to agent action methods and creates parameterized generations.
119
+ #
120
+ # @param method_name [Symbol] the name of the action method being called
121
+ # @param args [Array] arguments to pass to the action method
122
+ # @return [ActiveAgent::Parameterized::Generation] a generation
123
+ # instance with the stored parameters
124
+ # @raise [NoMethodError] if the method doesn't exist on the agent class
125
+ def method_missing(method_name, ...)
126
+ if @agent.public_instance_methods.include?(method_name)
127
+ ActiveAgent::Parameterized::Generation.new(@agent, method_name, @params, ...)
128
+ else
129
+ super
130
+ end
131
+ end
132
+
133
+ # @param method [Symbol] the method name to check
134
+ # @param include_all [Boolean] whether to include private and protected methods
135
+ # @return [Boolean] true if the agent responds to the method
136
+ def respond_to_missing?(method, include_all = false)
137
+ @agent.respond_to?(method, include_all)
138
+ end
139
+ end
140
+
141
+ # A specialized generation class that handles parameterized agent actions.
142
+ #
143
+ # This class extends {ActiveAgent::Generation} to support passing parameters
144
+ # to agent instances before processing actions. It ensures parameters are
145
+ # properly set both for immediate processing and when enqueuing background jobs.
146
+ #
147
+ # @api private
148
+ class Generation < ActiveAgent::Generation
149
+ # @param agent_class [Class] the agent class
150
+ # @param action [Symbol, String] the action method name
151
+ # @param params [Hash] the parameters to set on the agent instance
152
+ # @param args [Array] additional arguments for the action method
153
+ def initialize(agent_class, action, params, ...)
154
+ super(agent_class, action, ...)
155
+ @params = params
156
+ end
157
+
158
+ private
159
+
160
+ # Creates and processes an agent instance with parameters set.
161
+ #
162
+ # @return [ActiveAgent::Base] the processed agent instance with params
163
+ def agent
164
+ @agent ||= agent_class.new.tap do |agent|
165
+ agent.params = @params
166
+ agent.process(action_name, *args, **kwargs)
167
+ end
168
+ end
169
+
170
+ # Enqueues a generation job with parameters included.
171
+ #
172
+ # This method ensures that when a parameterized generation is enqueued,
173
+ # the parameters are passed to the background job so they can be
174
+ # properly set when the job executes.
175
+ #
176
+ # @param generation_method [Symbol, String] the generation method to call
177
+ # @param job_options [Hash] options to pass to the job (e.g., queue, priority)
178
+ # @return [Object] the enqueued job instance
179
+ def enqueue_generation(generation_method, job_options = {})
180
+ if processed?
181
+ super
182
+ else
183
+ agent_class.generation_job.set(job_options).perform_later(
184
+ agent_class.name, action_name.to_s, generation_method.to_s, params: @params, args: args, kwargs: kwargs
185
+ )
186
+ end
187
+ end
188
+ end
189
+
190
+ # A specialized generation class for direct prompt/embed calls without actions.
191
+ #
192
+ # This class handles cases where you want to call Agent.prompt(...).generate_now
193
+ # or Agent.embed(...).generate_now without defining an action method.
194
+ #
195
+ # @api private
196
+ class DirectGeneration < Generation
197
+ # @param agent_class [Class] the agent class
198
+ # @param generation_type [Symbol] either :prompt or :embed
199
+ # @param params [Hash] the parameters to set on the agent instance
200
+ # @param args [Array] messages for prompt or input for embed
201
+ # @param options [Hash] additional options (temperature, model, etc.)
202
+ def initialize(agent_class, generation_type, params, *args, **options)
203
+ @generation_type = generation_type
204
+ @direct_args = args
205
+ @direct_options = options
206
+
207
+ # Use a synthetic action name that won't conflict with real methods
208
+ super(agent_class, :"__direct_#{generation_type}__", params)
209
+ end
210
+
211
+ # Override generate_now to route to correct method based on generation type
212
+ def generate_now
213
+ case @generation_type
214
+ when :prompt
215
+ prompt_now
216
+ when :embed
217
+ embed_now
218
+ end
219
+ end
220
+
221
+ # Override generate_now! to route to correct method based on generation type
222
+ def generate_now!
223
+ case @generation_type
224
+ when :prompt
225
+ prompt_now!
226
+ when :embed
227
+ # For embed, we don't have a separate embed_now! method, so use embed_now
228
+ embed_now
229
+ end
230
+ end
231
+
232
+ # Generates a preview based on generation type.
233
+ #
234
+ # @return [String] markdown-formatted preview for prompt generations
235
+ # @raise [NotImplementedError] for embed generations (not yet supported)
236
+ def preview
237
+ case @generation_type
238
+ when :prompt
239
+ prompt_preview
240
+ when :embed
241
+ raise NotImplementedError, "Embed previewing is not supported"
242
+ end
243
+ end
244
+
245
+ private
246
+
247
+ # Creates and processes an agent instance for direct generation.
248
+ #
249
+ # Instead of calling a real action method, this directly calls the
250
+ # prompt() or embed() method on the agent instance with the provided arguments.
251
+ #
252
+ # @return [ActiveAgent::Base] the processed agent instance
253
+ def agent
254
+ @agent ||= agent_class.new.tap do |agent|
255
+ agent.params = @params
256
+
257
+ # Directly call prompt or embed method instead of processing an action
258
+ case @generation_type
259
+ when :prompt
260
+ agent.send(:prompt, *@direct_args, **@direct_options)
261
+ when :embed
262
+ agent.send(:embed, *@direct_args, **@direct_options)
263
+ end
264
+ end
265
+ end
266
+
267
+ # Enqueues a direct generation job.
268
+ #
269
+ # @param generation_method [Symbol, String] the generation method to call
270
+ # @param job_options [Hash] options to pass to the job
271
+ # @return [Object] the enqueued job instance
272
+ def enqueue_generation(generation_method, job_options = {})
273
+ if processed?
274
+ super
275
+ else
276
+ # For direct generations, we need to store the generation type and options
277
+ agent_class.generation_job.set(job_options).perform_later(
278
+ agent_class.name,
279
+ action_name.to_s,
280
+ generation_method.to_s,
281
+ params: @params,
282
+ args: args,
283
+ kwargs: kwargs,
284
+ direct_generation_type: @generation_type,
285
+ direct_args: @direct_args,
286
+ direct_options: @direct_options
287
+ )
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../providers/_base_provider"
4
+
5
+ module ActiveAgent
6
+ # Configures and manages AI provider integration for action prompts.
7
+ module Provider
8
+ extend ActiveSupport::Concern
9
+
10
+ # "Your tacky and I hate you" - Billy, https://youtu.be/dsheboxJNgQ?si=tzDlJ7sdSxM4RjSD
11
+ PROVIDER_SERVICE_NAMES_REMAPS = {
12
+ "Openrouter" => "OpenRouter",
13
+ "Openai" => "OpenAI"
14
+ }
15
+
16
+ included do
17
+ class_attribute :_prompt_provider_klass, instance_accessor: false, instance_predicate: false
18
+ class_attribute :_embed_provider_klass, instance_accessor: false, instance_predicate: false
19
+
20
+ delegate :prompt_provider_klass, :embed_provider_klass, to: :class
21
+ end
22
+
23
+ class_methods do
24
+ # Sets the prompt provider for this class.
25
+ #
26
+ # @param reference [Symbol, String, ActiveAgent::Provider::BaseProvider, Anthropic::Client, OpenAI::Client]
27
+ # Provider identifier, instance, or client
28
+ # @raise [ArgumentError] if reference type is unsupported
29
+ # @return [void]
30
+ def prompt_provider=(reference)
31
+ case reference
32
+ when Symbol, String
33
+ self._prompt_provider_klass = configuration(reference)
34
+
35
+ when ActiveAgent::Providers::BaseProvider
36
+ self._prompt_provider_klass = reference
37
+
38
+ when ->(ref) { defined?(::Anthropic) && ref.is_a?(::Anthropic::Client) }
39
+ self._prompt_provider_klass = provider_load("Anthropic")
40
+
41
+ when ->(ref) { defined?(::OpenAI) && ref.is_a?(::OpenAI::Client) }
42
+ self._prompt_provider_klass = provider_load("OpenAI")
43
+ else
44
+ raise ArgumentError
45
+ end
46
+ end
47
+
48
+ # Sets the embed provider for this class.
49
+ #
50
+ # @param reference [Symbol, String, ActiveAgent::Provider::BaseProvider, Anthropic::Client, OpenAI::Client]
51
+ # Provider identifier, instance, or client
52
+ # @raise [ArgumentError] if reference type is unsupported
53
+ # @return [void]
54
+ def embed_provider=(reference)
55
+ case reference
56
+ when Symbol, String
57
+ self._embed_provider_klass = configuration(reference)
58
+
59
+ when ActiveAgent::Providers::BaseProvider
60
+ self._embed_provider_klass = reference
61
+
62
+ when ->(ref) { defined?(::OpenAI) && ref.is_a?(::OpenAI::Client) }
63
+ self._embed_provider_klass = provider_load("OpenAI")
64
+ else
65
+ raise ArgumentError
66
+ end
67
+ end
68
+
69
+ # Loads provider class from configuration.
70
+ #
71
+ # @param reference [Symbol, String] Provider identifier
72
+ # @param options [Hash] Additional configuration options
73
+ # @return [Class] Provider class
74
+ # @raise [RuntimeError] if provider fails to load
75
+ def provider_setup(reference, **options)
76
+ type = reference.to_sym
77
+ config = { service: type.to_s.camelize }.merge(provider_config_load(type)).merge(options)
78
+ provider_load(config[:service])
79
+
80
+ rescue LoadError => e
81
+ raise RuntimeError, "Failed to load provider #{type}: #{e.message}"
82
+ end
83
+ alias configuration provider_setup
84
+
85
+ # Retrieves provider configuration.
86
+ #
87
+ # @param provider_type [Symbol, String] Provider identifier
88
+ # @return [Hash] Configuration hash with symbolized keys
89
+ def provider_config_load(provider_type)
90
+ path = [ ENV["RAILS_ENV"], provider_type.to_s ].compact
91
+
92
+ path.length.downto(1).map do |index|
93
+ ActiveAgent.configuration.dig(*path[(path.length - index)..])
94
+ end.compact.first&.deep_symbolize_keys || {}
95
+ end
96
+
97
+ # Loads provider class by service name.
98
+ #
99
+ # @param service_name [String] Service name (e.g., "OpenAI", "Anthropic")
100
+ # @return [Class] Provider class
101
+ def provider_load(service_name)
102
+ require "active_agent/providers/#{service_name.underscore}_provider"
103
+
104
+ service_name = Hash.new(service_name).merge!(PROVIDER_SERVICE_NAMES_REMAPS)[service_name]
105
+
106
+ ActiveAgent::Providers.const_get("#{service_name.camelize}Provider")
107
+ end
108
+
109
+ # Returns the configured prompt provider class.
110
+ #
111
+ # @return [Class, nil] Prompt provider class if set
112
+ def prompt_provider_klass = _prompt_provider_klass
113
+
114
+ # Returns the configured embed provider class.
115
+ #
116
+ # @return [Class, nil] Embed provider class if set
117
+ def embed_provider_klass = _embed_provider_klass
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Configures asynchronous generation via Active Job.
5
+ #
6
+ # Provides class attributes to customize which job class processes
7
+ # queued generations and which queue they run on. Enables agents to
8
+ # defer prompt generation and embedding operations for background processing.
9
+ #
10
+ # @example Custom job class
11
+ # class MyAgent < ActiveAgent::Base
12
+ # self.generation_job = CustomGenerationJob
13
+ # end
14
+ #
15
+ # @example Custom queue name
16
+ # class PriorityAgent < ActiveAgent::Base
17
+ # self.generate_later_queue_name = :high_priority
18
+ # end
19
+ #
20
+ # @see ActiveAgent::GenerationJob
21
+ module Queueing
22
+ extend ActiveSupport::Concern
23
+
24
+ included do
25
+ # Job class used to process queued generations.
26
+ #
27
+ # @return [Class] defaults to ActiveAgent::GenerationJob
28
+ class_attribute :generation_job, default: ::ActiveAgent::GenerationJob
29
+
30
+ # Queue name for generation jobs.
31
+ #
32
+ # @return [Symbol] defaults to :agents
33
+ class_attribute :generate_later_queue_name, default: :agents
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides exception handling for action prompts using `rescue_from` declarations.
5
+ #
6
+ # Handler methods must be public or protected because ActiveSupport::Rescuable
7
+ # uses `Kernel#method()` for lookup.
8
+ #
9
+ # @see https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/rescue.rb
10
+ # @see ActiveSupport::Rescuable
11
+ module Rescue
12
+ extend ActiveSupport::Concern
13
+ include ActiveSupport::Rescuable
14
+
15
+ class_methods do
16
+ # Finds and instruments the rescue handler for an exception.
17
+ #
18
+ # @param exception [Exception] the exception to handle
19
+ # @return [Proc, nil] the handler proc if found, nil otherwise
20
+ # @api private
21
+ # def handler_for_rescue(exception, ...)
22
+ # if (handler = super)
23
+ # ActiveSupport::Notifications.instrument("rescue_from_callback.active_agent", exception:)
24
+ # handler
25
+ # end
26
+ # end
27
+ end
28
+
29
+ # Yields to block with exception handling.
30
+ # Rescues using registered handlers or re-raises.
31
+ #
32
+ # @yield block to execute with exception handling
33
+ # @raise [Exception] if no handler is registered for the exception
34
+ def handle_exceptions
35
+ yield
36
+ rescue Exception => exception
37
+ rescue_with_handler(exception) || raise
38
+ end
39
+
40
+ private
41
+
42
+ # Processes the prompt with exception handling.
43
+ #
44
+ # Overrides parent to rescue exceptions using registered handlers.
45
+ #
46
+ # @raise [Exception] if no handler is registered for the exception
47
+ # @api private
48
+ def process(...)
49
+ super
50
+ rescue Exception => exception
51
+ rescue_with_handler(exception) || raise
52
+ end
53
+
54
+ # Returns proc that rescues exceptions using registered handlers.
55
+ #
56
+ # @return [Proc]
57
+ # @api private
58
+ def exception_handler
59
+ proc do |exception|
60
+ rescue_with_handler(exception)
61
+ end
62
+ end
63
+ end
64
+ end