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
@@ -1,46 +1,396 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_agent/action_prompt"
4
- require "active_agent/prompt_helper"
5
- require "active_agent/action_prompt/base"
6
-
7
- # The ActiveAgent module provides a framework for creating agents that can generate content
8
- # and handle various actions. The Base class within this module extends AbstractController::Base
9
- # and includes several modules to provide additional functionality such as callbacks, generation
10
- # methods, and rescuable actions.
11
- #
12
- # The Base class defines several class methods for registering and unregistering observers and
13
- # interceptors, as well as methods for generating content with a specified provider and streaming
14
- # content. It also provides methods for setting default parameters and handling prompts.
15
- #
16
- # The instance methods in the Base class include methods for performing generation, processing
17
- # actions, and handling headers and attachments. The class also defines a NullPrompt class for
18
- # handling cases where no prompt is provided.
19
- #
20
- # The Base class uses ActiveSupport::Notifications for instrumentation and provides several
21
- # private methods for setting payloads, applying defaults, and collecting responses from blocks,
22
- # text, or templates.
23
- #
24
- # The class also includes several protected instance variables and defines hooks for loading
25
- # additional functionality.
3
+ require "active_support/core_ext/hash/except"
4
+ require "active_support/core_ext/module/anonymous"
5
+ require "active_support/core_ext/string/inflections"
6
+
7
+ require "active_agent/concerns/callbacks"
8
+ require "active_agent/concerns/observers"
9
+ require "active_agent/concerns/parameterized"
10
+ require "active_agent/concerns/preview"
11
+ require "active_agent/concerns/provider"
12
+ require "active_agent/concerns/queueing"
13
+ require "active_agent/concerns/rescue"
14
+ require "active_agent/concerns/streaming"
15
+ require "active_agent/concerns/tooling"
16
+ require "active_agent/concerns/view"
17
+
18
+ require "active_agent/providers/log_subscriber"
19
+
26
20
  module ActiveAgent
27
- class Base < ActiveAgent::ActionPrompt::Base
28
- # This class is the base class for agents in the ActiveAgent framework.
29
- # It is built on top of ActionPrompt which provides methods for generating content, handling actions, and managing prompts.
30
- # ActiveAgent::Base is designed to be extended by specific agent implementations.
31
- # It provides a common set of agent actions for self-contained agents that can determine their own actions using all available actions.
32
- # Base actions include: prompt_context, continue, reasoning, reiterate, and conclude
33
- def prompt_context(additional_options = {})
34
- prompt(
35
- {
36
- stream: params[:stream],
37
- messages: params[:messages],
38
- message: params[:message],
39
- context_id: params[:context_id],
40
- options: params[:options],
41
- mcp_servers: params[:mcp_servers]
42
- }.merge(additional_options)
21
+ # Provides AI-powered agents with prompt generation, tool calling, and conversation management.
22
+ #
23
+ # @example Basic agent
24
+ # class MyAgent < ActiveAgent::Base
25
+ # generate_with :openai, model: "gpt-4"
26
+ #
27
+ # def greet
28
+ # prompt instructions: "Greet the user warmly"
29
+ # end
30
+ # end
31
+ #
32
+ # @abstract
33
+ class Base < AbstractController::Base
34
+ abstract!
35
+
36
+ include AbstractController::Rendering
37
+ include AbstractController::Logger
38
+ include AbstractController::Helpers
39
+ include AbstractController::Translation
40
+ include AbstractController::AssetPaths
41
+ include AbstractController::Callbacks
42
+ include AbstractController::Caching
43
+
44
+ include Callbacks
45
+ include Parameterized
46
+ include Provider
47
+ include Queueing
48
+ include Rescue
49
+ include Streaming
50
+ include Tooling
51
+ include View
52
+
53
+ include Observers
54
+ include Previews
55
+
56
+ PROTECTED_OPTIONS = %i[exception_handler stream_broadcaster tools_function]
57
+ PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [ :@_action_has_layout ]
58
+
59
+ # Logger instance for agent operations.
60
+ #
61
+ # Defaults to Rails.logger when used in Rails applications.
62
+ # Must conform to Log4r or Ruby Logger interface.
63
+ #
64
+ # @return [Logger, nil]
65
+ cattr_accessor :logger
66
+
67
+ class_attribute :prompt_options
68
+ class_attribute :embed_options
69
+
70
+ class << self
71
+ class_attribute :default_params, default: {
72
+ mime_version: "1.0",
73
+ charset: "UTF-8",
74
+ content_type: "text/plain",
75
+ parts_order: [ "text/markdown", "text/plain", "text/enriched", "text/html" ]
76
+ }.freeze
77
+
78
+ # Sets default parameters applied to all actions unless overridden.
79
+ #
80
+ # @param value [Hash, nil] parameters to merge, or nil to return current defaults
81
+ # @return [Hash]
82
+ #
83
+ # @example
84
+ # default temperature: 0.7, max_tokens: 1000
85
+ def default(value = nil)
86
+ self.default_params = default_params.merge(value).freeze if value
87
+ default_params
88
+ end
89
+ alias_method :default_params=, :default
90
+ end
91
+
92
+ # Configures generation provider and options for prompt generation.
93
+ #
94
+ # Options are merged with global provider config and inherited parent class options.
95
+ # Instructions are never inherited from parent classes.
96
+ #
97
+ # @param provider_reference [Symbol, String] generation provider (:openai, :anthropic, etc.)
98
+ # @param agent_options [Hash] configuration options shared across actions
99
+ # @return [void]
100
+ #
101
+ # @example
102
+ # generate_with :openai, model: "gpt-4", temperature: 0.7
103
+ def self.generate_with(provider_reference, **agent_options)
104
+ self.prompt_provider = provider_reference
105
+
106
+ global_options = provider_config_load(provider_reference)
107
+ inherited_options = (self.prompt_options || {}).except(:instructions) # Don't inherit instructions from parent
108
+
109
+ # Different Service, different APIs
110
+ if global_options[:service] != inherited_options[:service]
111
+ inherited_options.extract!(:service, :api_version)
112
+ end
113
+
114
+ self.prompt_options = global_options.merge(inherited_options).merge(agent_options)
115
+ end
116
+
117
+ # Configures embedding provider and options for embedding generation.
118
+ #
119
+ # @param provider_reference [Symbol, String] embedding provider (:openai, :anthropic, etc.)
120
+ # @param agent_options [Hash] configuration options for embedding generation
121
+ # @return [void]
122
+ #
123
+ # @example
124
+ # embed_with :openai, model: "text-embedding-3-large"
125
+ def self.embed_with(provider_reference, **agent_options)
126
+ self.embed_provider = provider_reference
127
+
128
+ global_options = provider_config_load(provider_reference)
129
+ inherited_options = self.embed_options || {}
130
+
131
+ self.embed_options = global_options.merge(inherited_options).merge(agent_options)
132
+ end
133
+
134
+ # @api private
135
+ def self.method_missing(method_name, ...)
136
+ if action_methods.include?(method_name.name)
137
+ Generation.new(self, method_name, ...)
138
+ else
139
+ super
140
+ end
141
+ end
142
+ private_class_method :method_missing
143
+
144
+ # @api private
145
+ def self.respond_to_missing?(method, include_all = false)
146
+ action_methods.include?(method.name) || super
147
+ end
148
+ private_class_method :respond_to_missing?
149
+
150
+ delegate :agent_name, to: :class
151
+
152
+ # @!attribute [w] agent_name
153
+ # Agent name override for custom view lookup paths.
154
+ # @return [String]
155
+ attr_writer :agent_name
156
+ alias_method :controller_path, :agent_name
157
+
158
+ # @!attribute [rw] prompt_options
159
+ # Action-level prompt options merged with agent prompt options.
160
+ # @return [Hash]
161
+ attr_internal :prompt_options
162
+
163
+ # @!attribute [rw] embed_options
164
+ # Action-level embed options merged with agent embed options.
165
+ # @return [Hash]
166
+ attr_internal :embed_options
167
+
168
+ # @api private
169
+ def initialize # :nodoc:
170
+ super
171
+ self.prompt_options = (self.class.prompt_options&.deep_dup || {}).except(:trace_id)
172
+ self.embed_options = (self.class.embed_options&.deep_dup || {}).except(:trace_id)
173
+ end
174
+
175
+ # Agent name used as a path for view lookup.
176
+ #
177
+ # @return [String] agent name or "anonymous" for anonymous agents
178
+ def agent_name
179
+ @agent_name ||= self.class.anonymous? ? "anonymous" : self.class.name.underscore
180
+ end
181
+
182
+ # Processes an agent action with ActiveSupport::Notifications instrumentation.
183
+ #
184
+ # Actions are triggered externally via Agent.action_name.generate_now or internally
185
+ # through tool calls during AI generation workflows.
186
+ #
187
+ # @param method_name [Symbol, String] action method to process
188
+ # @param args [Array]
189
+ # @param kwargs [Hash]
190
+ # @return [void]
191
+ # @api private
192
+ def process(method_name, *args, **kwargs)
193
+ payload = { agent: self.class.name, action: method_name, args:, kwargs: }
194
+
195
+ ActiveSupport::Notifications.instrument("process.active_agent", payload) do
196
+ super
197
+ end
198
+ end
199
+
200
+ # Merges action-level parameters into prompt context.
201
+ #
202
+ # Processing is deferred until execution to allow local overrides.
203
+ #
204
+ # @param messages [Array<String, Hash>] message strings or hashes to add to conversation
205
+ # @param options [Hash] parameters to merge into prompt context
206
+ # @return [void]
207
+ #
208
+ # @example
209
+ # def my_action
210
+ # prompt "User message", temperature: 0.8, instructions: "Be creative"
211
+ # end
212
+ def prompt(*messages, **options)
213
+ # Extract message/messages from options and add to messages array
214
+ messages += options.extract!(:message, :messages).values.flatten.compact
215
+
216
+ # Extract image and document attachments
217
+ messages += options.extract!(:image, :document).map { |k, v| { k => v } }
218
+
219
+ prompt_options.merge!({ messages: }.compact_blank.merge!(options))
220
+ end
221
+
222
+ # Merges action-level parameters into embedding context.
223
+ #
224
+ # @param input [String, Array<String>, nil] text to embed
225
+ # @param options [Hash] parameters to merge into embedding context
226
+ # @return [void]
227
+ #
228
+ # @example With direct input
229
+ # embed "Text to embed", model: "text-embedding-3-large"
230
+ #
231
+ # @example With template
232
+ # embed locals: { text: "Custom text" }
233
+ def embed(input = nil, **options)
234
+ new_options = { input: }.compact_blank.merge!(options)
235
+ embed_options.merge!(new_options)
236
+ end
237
+
238
+ # Executes prompt generation using configured provider and options.
239
+ #
240
+ # Triggered by generate_now or generate_later workflows. Templates are
241
+ # rendered as late as possible to allow local overrides.
242
+ #
243
+ # @return [ActiveAgent::Providers::Response]
244
+ # @raise [RuntimeError] if no prompt provider is configured
245
+ def process_prompt
246
+ fail "Prompt Provider not Configured" unless prompt_provider_klass
247
+
248
+ run_callbacks(:generation) do
249
+ run_callbacks(:prompting) do
250
+ parameters = prepare_prompt_parameters
251
+
252
+ prompt_provider_klass.new(**parameters).prompt
253
+ end
254
+ end
255
+ end
256
+
257
+ alias_method :process_prompt!, :process_prompt
258
+
259
+ # Generates a preview of the prompt without executing generation.
260
+ #
261
+ # Useful for debugging and inspecting the final prompt that would be
262
+ # sent to the provider, including rendered templates and merged parameters.
263
+ #
264
+ # @return [String, Hash] preview format depends on provider implementation
265
+ # @raise [RuntimeError] if no prompt provider is configured
266
+ def preview_prompt
267
+ fail "Prompt Provider not Configured" unless prompt_provider_klass
268
+
269
+ parameters = prepare_prompt_parameters
270
+
271
+ prompt_provider_klass.new(**parameters).preview
272
+ end
273
+
274
+ # Executes embedding generation using configured provider and options.
275
+ #
276
+ # Templates are rendered as late as possible to allow local overrides.
277
+ #
278
+ # @return [ActiveAgent::Providers::Response]
279
+ # @raise [RuntimeError] if no embed provider is configured
280
+ def process_embed
281
+ fail "Embed Provider not Configured" unless embed_provider_klass
282
+
283
+ run_callbacks(:generation) do
284
+ run_callbacks(:embedding) do
285
+ parameters = prepare_embed_parameters
286
+
287
+ embed_provider_klass.new(**parameters).embed
288
+ end
289
+ end
290
+ end
291
+
292
+ # @api private
293
+ def action_methods
294
+ super - ActiveAgent::Base.public_instance_methods(false).map(&:to_s) - [ action_name ]
295
+ end
296
+
297
+ private
298
+
299
+ # @api private
300
+ def prepare_prompt_parameters
301
+ parameters = prompt_options.deep_dup.except(:locals, *PROTECTED_OPTIONS)
302
+
303
+ # Render out proc/lamda attributes before rendering templates
304
+ parameters.deep_transform_values! { _1.respond_to?(:call) ? _1.call : _1 }
305
+
306
+ # Apply Callbacks
307
+ parameters.merge!(
308
+ trace_id: prompt_options[:trace_id] || SecureRandom.uuid,
309
+ exception_handler:,
310
+ stream_broadcaster:,
311
+ tools_function:,
43
312
  )
313
+
314
+ # Apply Templates
315
+ parameters = process_prompt_templates(parameters, prompt_options)
316
+
317
+ parameters.compact
318
+ end
319
+
320
+ # @api private
321
+ def prepare_embed_parameters
322
+ parameters = embed_options.deep_dup.except(:locals, *PROTECTED_OPTIONS)
323
+
324
+ # Render out proc/lamda attributes before rendering templates
325
+ parameters.deep_transform_values! { _1.respond_to?(:call) ? _1.call : _1 }
326
+
327
+ # Apply Callbacks
328
+ parameters.merge!(
329
+ trace_id: prompt_options[:trace_id] || SecureRandom.uuid,
330
+ exception_handler:
331
+ ).compact!
332
+
333
+ # Fallback to input from template if no input provided, rendered as late as
334
+ # possible to allow local overrides.
335
+ if parameters[:input].blank?
336
+ template_input = embed_view_input(action_name, strict: true, **(embed_options[:locals] || {}))
337
+ parameters[:input] = template_input if template_input.present?
338
+ end
339
+
340
+ parameters.compact
44
341
  end
342
+
343
+ # @api private
344
+ def process_prompt_templates(parameters, prompt_options)
345
+ # Resolve Instructions
346
+ parameters[:instructions] = prompt_view_instructions(parameters[:instructions])
347
+
348
+ # Resolve Message Template as fallback
349
+ if (parameters[:messages] || parameters[:input]).blank?
350
+ template_message = prompt_view_message(action_name, strict: parameters[:instructions].blank?, **(prompt_options[:locals] || {}))
351
+ parameters[:messages] = [ template_message ] if template_message.present?
352
+ end
353
+
354
+ # Resolve Response Format
355
+ if parameters[:response_format]
356
+ parameters[:response_format] = process_prompt_templates_response_format(parameters[:response_format])
357
+ end
358
+
359
+ parameters
360
+ end
361
+
362
+ # @api private
363
+ def process_prompt_templates_response_format(response_format)
364
+ if response_format.is_a?(Symbol) || response_format.is_a?(String)
365
+ response_format = { type: response_format.to_s }
366
+ end
367
+
368
+ if response_format[:type].to_sym == :json_schema
369
+ response_format[:json_schema] = prompt_view_schema(response_format[:json_schema])
370
+ response_format[:json_schema].deep_transform_keys! { _1.to_s.camelize(:lower) }
371
+ end
372
+
373
+ response_format
374
+ end
375
+
376
+ # @api private
377
+ def instrument_payload(key)
378
+ {
379
+ agent: agent_name,
380
+ key: key
381
+ }
382
+ end
383
+
384
+ # @api private
385
+ def instrument_name
386
+ "active_agent"
387
+ end
388
+
389
+ # @api private
390
+ def _protected_ivars
391
+ PROTECTED_IVARS
392
+ end
393
+
394
+ ActiveSupport.run_load_hooks(:active_agent, self)
45
395
  end
46
396
  end
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+
5
+ module ActiveAgent
6
+ # Provides callback hooks for generation, prompting, and embedding lifecycles.
7
+ #
8
+ # Enables agents to execute custom logic before, after, or around AI operations.
9
+ # Callbacks support conditional execution via `:if` and `:unless` options, and
10
+ # after callbacks are skipped when the chain is terminated with `throw :abort`.
11
+ #
12
+ # == Callback Types
13
+ #
14
+ # Each lifecycle supports three timing hooks:
15
+ # * +before_*+ - executes before the operation
16
+ # * +after_*+ - executes after the operation (skipped if aborted)
17
+ # * +around_*+ - wraps the operation (must call +yield+)
18
+ #
19
+ # == Lifecycle Hierarchies
20
+ #
21
+ # * +generation+ - wraps both prompting and embedding operations
22
+ # * +prompting+ - specific to prompt execution
23
+ # * +embedding+ - specific to embedding operations
24
+ #
25
+ # Use +*_generation+ callbacks for cross-cutting concerns like rate limiting,
26
+ # authentication, and logging that apply to all AI operations.
27
+ #
28
+ # == Callback Control
29
+ #
30
+ # * +prepend_*+ - inserts callback at the beginning of the chain
31
+ # * +append_*+ - adds callback at the end (same as base methods)
32
+ # * +skip_*+ - removes a previously defined callback
33
+ #
34
+ # @example Rate limiting with generation callbacks
35
+ # class MyAgent < ActiveAgent::Base
36
+ # before_generation :check_rate_limit
37
+ # after_generation :record_usage
38
+ #
39
+ # def check_rate_limit
40
+ # raise RateLimitExceeded if RateLimiter.exceeded?(user_id)
41
+ # end
42
+ #
43
+ # def record_usage
44
+ # RateLimiter.increment(user_id)
45
+ # end
46
+ # end
47
+ #
48
+ # @example Before prompting callback
49
+ # class MyAgent < ActiveAgent::Base
50
+ # before_prompt :load_context
51
+ #
52
+ # def load_context
53
+ # @user_data = User.find(params[:user_id])
54
+ # end
55
+ # end
56
+ #
57
+ # @example After prompting with condition
58
+ # class MyAgent < ActiveAgent::Base
59
+ # after_prompt :log_response, if: :production?
60
+ #
61
+ # def log_response
62
+ # Logger.info("Generated response: #{context.messages.last}")
63
+ # end
64
+ # end
65
+ #
66
+ # @example Around embedding for timing
67
+ # class MyAgent < ActiveAgent::Base
68
+ # around_embed :measure_time
69
+ #
70
+ # def measure_time
71
+ # start = Time.now
72
+ # yield
73
+ # Rails.logger.info("Embedding took #{Time.now - start}s")
74
+ # end
75
+ # end
76
+ #
77
+ # @example Prepending and skipping callbacks
78
+ # class MyAgent < ActiveAgent::Base
79
+ # prepend_before_prompt :urgent_check # Runs first
80
+ # before_prompt :normal_check # Runs second
81
+ #
82
+ # skip_after_prompt :log_response # Removes inherited callback
83
+ # end
84
+ module Callbacks
85
+ extend ActiveSupport::Concern
86
+
87
+ included do
88
+ include ActiveSupport::Callbacks
89
+ define_callbacks :generation, skip_after_callbacks_if_terminated: true
90
+ define_callbacks :prompting, skip_after_callbacks_if_terminated: true
91
+ define_callbacks :embedding, skip_after_callbacks_if_terminated: true
92
+ end
93
+
94
+ module ClassMethods
95
+ # Registers callbacks for the prompting lifecycle.
96
+ #
97
+ # Dynamically defines callback methods for each timing hook.
98
+ # Multiple callbacks execute in registration order for before/around,
99
+ # and reverse order for after.
100
+ #
101
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
102
+ # @param blk [Proc] optional block to execute instead of named method
103
+ # @yield callback implementation when using block form
104
+ #
105
+ # @example Multiple before callbacks
106
+ # before_prompt :load_user, :check_permissions
107
+ #
108
+ # @example Block syntax
109
+ # after_prompt do
110
+ # cache.write("last_response", context.messages.last)
111
+ # end
112
+ [ :before, :after, :around ].each do |callback|
113
+ define_method "#{callback}_prompt" do |*names, &blk|
114
+ _insert_callbacks(names, blk) do |name, options|
115
+ set_callback(:prompting, callback, name, options)
116
+ end
117
+ end
118
+
119
+ # Prepends a callback to the beginning of the prompting chain.
120
+ #
121
+ # Useful for ensuring critical setup runs before other callbacks.
122
+ #
123
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
124
+ # @param blk [Proc] optional block to execute
125
+ #
126
+ # @example Prepend urgent validation
127
+ # prepend_before_prompt :validate_api_key
128
+ define_method "prepend_#{callback}_prompt" do |*names, &blk|
129
+ _insert_callbacks(names, blk) do |name, options|
130
+ set_callback(:prompting, callback, name, options.merge(prepend: true))
131
+ end
132
+ end
133
+
134
+ # Skips a previously defined prompting callback.
135
+ #
136
+ # Useful for removing inherited callbacks or disabling callbacks
137
+ # conditionally in subclasses.
138
+ #
139
+ # @param names [Symbol, Array<Symbol>] method name(s) to skip
140
+ #
141
+ # @example Skip inherited callback
142
+ # skip_after_prompt :log_response
143
+ define_method "skip_#{callback}_prompt" do |*names|
144
+ _insert_callbacks(names) do |name, options|
145
+ skip_callback(:prompting, callback, name, options)
146
+ end
147
+ end
148
+
149
+ # Alias for explicit append behavior (same as base method).
150
+ alias_method :"append_#{callback}_prompt", :"#{callback}_prompt"
151
+
152
+ # Registers callbacks for the generation lifecycle.
153
+ #
154
+ # Generation callbacks wrap both prompting and embedding operations,
155
+ # making them ideal for cross-cutting concerns like rate limiting,
156
+ # authentication, logging, and resource management that apply to all
157
+ # AI operations.
158
+ #
159
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
160
+ # @param blk [Proc] optional block to execute instead of named method
161
+ # @yield callback implementation when using block form
162
+ #
163
+ # @example Rate limiting for all operations
164
+ # before_generation :check_rate_limit
165
+ # after_generation :record_usage
166
+ #
167
+ # @example Authentication check
168
+ # around_generation :with_api_key
169
+ define_method "#{callback}_generation" do |*names, &blk|
170
+ _insert_callbacks(names, blk) do |name, options|
171
+ set_callback(:generation, callback, name, options)
172
+ end
173
+ end
174
+
175
+ # Prepends a callback to the beginning of the generation chain.
176
+ #
177
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
178
+ # @param blk [Proc] optional block to execute
179
+ #
180
+ # @example Prepend rate limiting
181
+ # prepend_before_generation :check_rate_limit
182
+ define_method "prepend_#{callback}_generation" do |*names, &blk|
183
+ _insert_callbacks(names, blk) do |name, options|
184
+ set_callback(:generation, callback, name, options.merge(prepend: true))
185
+ end
186
+ end
187
+
188
+ # Skips a previously defined generation callback.
189
+ #
190
+ # @param names [Symbol, Array<Symbol>] method name(s) to skip
191
+ #
192
+ # @example Skip inherited callback
193
+ # skip_before_generation :check_rate_limit
194
+ define_method "skip_#{callback}_generation" do |*names|
195
+ _insert_callbacks(names) do |name, options|
196
+ skip_callback(:generation, callback, name, options)
197
+ end
198
+ end
199
+
200
+ # Alias for explicit append behavior (same as base method).
201
+ alias_method :"append_#{callback}_generation", :"#{callback}_generation"
202
+
203
+ # Registers callbacks for the embedding lifecycle.
204
+ #
205
+ # Behavior identical to prompting callbacks but invoked during
206
+ # embedding operations.
207
+ #
208
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
209
+ # @param blk [Proc] optional block to execute instead of named method
210
+ # @yield callback implementation when using block form
211
+ #
212
+ # @example Track embedding calls
213
+ # before_embed :increment_counter
214
+ # after_embed :store_embedding
215
+ define_method "#{callback}_embed" do |*names, &blk|
216
+ _insert_callbacks(names, blk) do |name, options|
217
+ set_callback(:embedding, callback, name, options)
218
+ end
219
+ end
220
+
221
+ # Prepends a callback to the beginning of the embedding chain.
222
+ #
223
+ # @param names [Symbol, Array<Symbol>] method name(s) to call
224
+ # @param blk [Proc] optional block to execute
225
+ #
226
+ # @example Prepend rate limiting
227
+ # prepend_before_embed :check_rate_limit
228
+ define_method "prepend_#{callback}_embed" do |*names, &blk|
229
+ _insert_callbacks(names, blk) do |name, options|
230
+ set_callback(:embedding, callback, name, options.merge(prepend: true))
231
+ end
232
+ end
233
+
234
+ # Skips a previously defined embedding callback.
235
+ #
236
+ # @param names [Symbol, Array<Symbol>] method name(s) to skip
237
+ #
238
+ # @example Skip inherited callback
239
+ # skip_before_embed :validate_input
240
+ define_method "skip_#{callback}_embed" do |*names|
241
+ _insert_callbacks(names) do |name, options|
242
+ skip_callback(:embedding, callback, name, options)
243
+ end
244
+ end
245
+
246
+ # Alias for explicit append behavior (same as base method).
247
+ alias_method :"append_#{callback}_embed", :"#{callback}_embed"
248
+ end
249
+ end
250
+ end
251
+ end