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,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides streaming callback support for agent classes.
5
+ #
6
+ # Callbacks can be registered for three points in the streaming lifecycle:
7
+ # - {on_stream_open} - invoked before the first chunk
8
+ # - {on_stream} - invoked for every chunk received
9
+ # - {on_stream_close} - invoked after the final chunk
10
+ #
11
+ # Callbacks automatically receive a {StreamChunk} parameter if they accept arguments.
12
+ #
13
+ # @example Basic usage with chunk parameter
14
+ # class MyPrompt < ActiveAgent::Base
15
+ # on_stream_open :setup_stream
16
+ # on_stream :log_chunk
17
+ # on_stream_close :cleanup_stream
18
+ #
19
+ # private
20
+ #
21
+ # def setup_stream(chunk)
22
+ # puts "Stream opening..."
23
+ # puts "First message: #{chunk.message}"
24
+ # end
25
+ #
26
+ # def log_chunk(chunk)
27
+ # print chunk.delta if chunk.delta
28
+ # end
29
+ #
30
+ # def cleanup_stream(chunk)
31
+ # puts "\nStream complete!"
32
+ # end
33
+ # end
34
+ #
35
+ # @example Usage without chunk parameter
36
+ # class MyPrompt < ActiveAgent::Base
37
+ # on_stream_open :initialize_counter
38
+ # on_stream :increment_counter
39
+ # on_stream_close :log_total
40
+ #
41
+ # private
42
+ #
43
+ # def initialize_counter
44
+ # @count = 0
45
+ # end
46
+ #
47
+ # def increment_counter
48
+ # @count += 1
49
+ # end
50
+ #
51
+ # def log_total
52
+ # puts "Total chunks: #{@count}"
53
+ # end
54
+ # end
55
+ #
56
+ # @example Using blocks
57
+ # class MyPrompt < ActiveAgent::Base
58
+ # on_stream do |chunk|
59
+ # Rails.logger.info("Received: #{chunk.delta}")
60
+ # end
61
+ # end
62
+ #
63
+ # @example With callback options
64
+ # class MyPrompt < ActiveAgent::Base
65
+ # on_stream :log_chunk, if: :debug_mode?
66
+ # on_stream_close :save_response, unless: :test_environment?
67
+ # end
68
+ module Streaming
69
+ extend ActiveSupport::Concern
70
+
71
+ # Data object representing a chunk of streamed content.
72
+ #
73
+ # @!attribute [r] message
74
+ # @return [Object] the complete message object from the provider
75
+ # @!attribute [r] delta
76
+ # @return [String, nil] the incremental content delta for this chunk
77
+ class StreamChunk < Data.define(:message, :delta); end
78
+
79
+ included do
80
+ include AbstractController::Callbacks
81
+
82
+ define_callbacks :stream_open
83
+ define_callbacks :stream
84
+ define_callbacks :stream_close
85
+
86
+ # Internal attribute to store the current streaming chunk.
87
+ #
88
+ # @api private
89
+ attr_internal :stream_chunk
90
+ end
91
+
92
+ class_methods do
93
+ # Defines a callback for when streaming opens.
94
+ #
95
+ # Invoked before the first chunk. Callbacks receive a {StreamChunk}
96
+ # if they accept arguments.
97
+ #
98
+ # @param names [Symbol] method names to call as callbacks
99
+ # @param block [Proc] optional block to execute as a callback
100
+ # @yield [chunk] passes the {StreamChunk} if the block accepts parameters
101
+ # @yieldparam chunk [StreamChunk] current stream chunk
102
+ # @option options [Symbol, Proc] :if condition for running the callback
103
+ # @option options [Symbol, Proc] :unless condition for skipping the callback
104
+ # @return [void]
105
+ #
106
+ # @example With method that accepts chunk
107
+ # on_stream_open :setup_streaming
108
+ #
109
+ # def setup_streaming(chunk)
110
+ # @buffer = []
111
+ # Rails.logger.info("Starting: #{chunk.message}")
112
+ # end
113
+ #
114
+ # @example With method that doesn't need chunk
115
+ # on_stream_open :initialize_buffer
116
+ #
117
+ # def initialize_buffer
118
+ # @buffer = []
119
+ # end
120
+ #
121
+ # @example With a block
122
+ # on_stream_open do |chunk|
123
+ # Rails.logger.info("Stream opening with message: #{chunk.message}")
124
+ # end
125
+ #
126
+ # @example With conditions
127
+ # on_stream_open :log_open, if: :logging_enabled?
128
+ def on_stream_open(*names, &block)
129
+ _stream_define_callback(:stream_open, *names, &block)
130
+ end
131
+
132
+ # Defines a callback for handling streaming responses.
133
+ #
134
+ # Invoked for every chunk received. Callbacks receive a {StreamChunk}
135
+ # if they accept arguments.
136
+ #
137
+ # @param names [Symbol] method names to call as callbacks
138
+ # @param block [Proc] optional block to execute as a callback
139
+ # @yield [chunk] passes the {StreamChunk} if the block accepts parameters
140
+ # @yieldparam chunk [StreamChunk] current stream chunk
141
+ # @option options [Symbol, Proc] :if condition for running the callback
142
+ # @option options [Symbol, Proc] :unless condition for skipping the callback
143
+ # @return [void]
144
+ #
145
+ # @example With method that accepts chunk
146
+ # on_stream :process_chunk
147
+ #
148
+ # def process_chunk(chunk)
149
+ # print chunk.delta if chunk.delta
150
+ # end
151
+ #
152
+ # @example With method that doesn't need chunk
153
+ # on_stream :increment_counter
154
+ #
155
+ # def increment_counter
156
+ # @chunk_count += 1
157
+ # end
158
+ #
159
+ # @example With a block
160
+ # on_stream do |chunk|
161
+ # print chunk.delta if chunk.delta
162
+ # end
163
+ #
164
+ # @example With conditions
165
+ # on_stream :buffer_chunk, unless: :direct_output?
166
+ def on_stream(*names, &block)
167
+ _stream_define_callback(:stream, *names, &block)
168
+ end
169
+
170
+ # Defines a callback for when streaming closes.
171
+ #
172
+ # Invoked after the final chunk. Callbacks receive a {StreamChunk}
173
+ # if they accept arguments.
174
+ #
175
+ # @param names [Symbol] method names to call as callbacks
176
+ # @param block [Proc] optional block to execute as a callback
177
+ # @yield [chunk] passes the {StreamChunk} if the block accepts parameters
178
+ # @yieldparam chunk [StreamChunk] current stream chunk
179
+ # @option options [Symbol, Proc] :if condition for running the callback
180
+ # @option options [Symbol, Proc] :unless condition for skipping the callback
181
+ # @return [void]
182
+ #
183
+ # @example With method that accepts chunk
184
+ # on_stream_close :save_response
185
+ #
186
+ # def save_response(chunk)
187
+ # Rails.logger.info("Complete: #{chunk.message}")
188
+ # end
189
+ #
190
+ # @example With method that doesn't need chunk
191
+ # on_stream_close :cleanup
192
+ #
193
+ # def cleanup
194
+ # @buffer = nil
195
+ # end
196
+ #
197
+ # @example With a block
198
+ # on_stream_close do |chunk|
199
+ # Rails.logger.info("Stream complete")
200
+ # end
201
+ #
202
+ # @example With conditions
203
+ # on_stream_close :persist_response, if: :should_save?
204
+ def on_stream_close(*names, &block)
205
+ _stream_define_callback(:stream_close, *names, &block)
206
+ end
207
+
208
+ # @api private
209
+ # @param callback_name [Symbol] callback type (:stream_open, :stream, :stream_close)
210
+ # @param names [Array<Symbol>] method names or procs to register
211
+ # @param block [Proc] optional block to register
212
+ # @return [void]
213
+ def _stream_define_callback(callback_name, *names, &block)
214
+ _insert_callbacks(names, block) do |name, options|
215
+ wrapper = _stream_define_callback_wrapper(callback_name, name)
216
+ set_callback(callback_name, :before, wrapper, **options)
217
+ end
218
+ end
219
+
220
+ # @api private
221
+ # @param callback_name [Symbol] callback type
222
+ # @param method_ref [Symbol, Proc] method name or proc to wrap
223
+ # @return [Symbol] wrapper method name
224
+ def _stream_define_callback_wrapper(callback_name, method_ref)
225
+ if method_ref.is_a?(Proc)
226
+ _stream_define_callback_wrapper_proc(callback_name, method_ref)
227
+ else
228
+ _stream_define_callback_wrapper_name(callback_name, method_ref)
229
+ end
230
+ end
231
+
232
+ # @api private
233
+ # @param callback_name [Symbol] callback type
234
+ # @param method_name [Symbol] method name to wrap
235
+ # @return [Symbol] wrapper method name
236
+ def _stream_define_callback_wrapper_name(callback_name, method_name)
237
+ define_method(:"_#{callback_name}_#{method_name}") do
238
+ if method(method_name).arity.zero?
239
+ send(method_name)
240
+ else
241
+ send(method_name, stream_chunk)
242
+ end
243
+ end
244
+ end
245
+
246
+ # @api private
247
+ # @param callback_name [Symbol] callback type
248
+ # @param method_proc [Proc] proc to wrap
249
+ # @return [Symbol] wrapper method name
250
+ def _stream_define_callback_wrapper_proc(callback_name, method_proc)
251
+ define_method(:"_#{callback_name}_#{method_proc.object_id}") do
252
+ if method_proc.arity.zero?
253
+ instance_exec(&method_proc)
254
+ else
255
+ instance_exec(stream_chunk, &method_proc)
256
+ end
257
+ end
258
+ end
259
+ end
260
+
261
+ private
262
+
263
+ # Returns a proc that runs streaming callbacks for provider execution.
264
+ #
265
+ # The returned proc creates a {StreamChunk} and triggers callbacks
266
+ # based on the type parameter (`:open`, `:update`, or `:close`).
267
+ #
268
+ # @return [Proc] callback proc that accepts (message, delta, type)
269
+ def stream_broadcaster
270
+ proc do |message, delta, type|
271
+ self.stream_chunk = StreamChunk.new(message, delta)
272
+
273
+ run_callbacks(:stream_open) if type == :open
274
+ run_callbacks(:stream)
275
+ run_callbacks(:stream_close) if type == :close
276
+
277
+ # Don't leak dirty context between callbacks or into userspace
278
+ self.stream_chunk = nil
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides tool/function calling support for agent classes.
5
+ #
6
+ # Enables agent classes to respond to tool calls from providers
7
+ # by routing them to the appropriate action methods.
8
+ module Tooling
9
+ extend ActiveSupport::Concern
10
+
11
+ # Returns a proc that handles tool/function calls from providers.
12
+ #
13
+ # The proc routes tool calls to the appropriate action method using
14
+ # the {#process} method.
15
+ #
16
+ # @return [Proc] callback proc that accepts (action_name, *args, **kwargs)
17
+ def tools_function
18
+ proc do |action_name, *args, **kwargs|
19
+ process(action_name, *args, **kwargs)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ # Provides template lookup and rendering for agent classes.
5
+ #
6
+ # Enables agents to render instructions, schemas, and messages from
7
+ # ERB templates with flexible directory structures and fallback paths.
8
+ module View
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include ActionView::Layouts
13
+ end
14
+
15
+ # Builds template lookup paths supporting both flat and nested directory structures.
16
+ #
17
+ # Templates are searched in priority order:
18
+ # - `app/views/{agent_name}/` (e.g., `app/views/support_agent/`)
19
+ # - `app/views/agents/{agent_without_suffix}/` (e.g., `app/views/agents/support/`)
20
+ #
21
+ # With action_name present:
22
+ # - `app/views/agents/{agent_without_suffix}/{action_name}/`
23
+ # - `app/views/{agent_name}/{action_name}/`
24
+ # - `app/views/{agent_name}/`
25
+ # - `app/views/agents/{agent_without_suffix}/`
26
+ #
27
+ # @return [Array<String>] ordered prefixes for template lookup
28
+ def _prefixes
29
+ @_prefixes ||= begin
30
+ # Get the base agent name (e.g., "statements_agent" or "view_test/test_agent")
31
+ base = agent_name
32
+
33
+ # Build the nested structure under agents/
34
+ # e.g., "agents/statements" for StatementsAgent
35
+ nested = "agents/#{base.delete_suffix("_agent")}"
36
+
37
+ # Build prefixes with action_name if present
38
+ if action_name.present?
39
+ # Priority order: nested/action, base/action, base, nested
40
+ [ "#{nested}/#{action_name}", "#{base}/#{action_name}", base, nested ]
41
+ else
42
+ # Priority order: base, nested
43
+ [ nested, base ]
44
+ end
45
+ end
46
+ end
47
+
48
+ ##### Instructions Templating ###########################################
49
+
50
+ # Prepares instructions from various input formats.
51
+ #
52
+ # Supported formats:
53
+ # - `String`: returned as-is
54
+ # - `Symbol`: invokes method with that name (like ActiveRecord callbacks)
55
+ # - `Array<String>`: returned as-is if all elements are strings
56
+ # - `Hash`: requires `:template` key, optional `:locals`
57
+ # - `nil` or `true`: renders default "instructions" template
58
+ #
59
+ # @param value [Hash, String, Symbol, Array<String>, Boolean, nil]
60
+ # @return [String, Array<String>, nil] nil if template not found
61
+ # @raise [ArgumentError] if format is invalid or Hash missing :template key
62
+ def prompt_view_instructions(value)
63
+ case value
64
+ when String
65
+ value.presence
66
+
67
+ when Symbol
68
+ send(value)
69
+
70
+ when Array
71
+ raise ArgumentError, "Instructions array must contain only strings" unless value.all?(String)
72
+ value.presence
73
+
74
+ when Hash
75
+ view_render_template(value[:template] || "instructions", strict: true, **value[:locals])
76
+
77
+ when nil, true
78
+ view_render_template("instructions", strict: value == true, **(params.dig(:instructions, :locals) || {}))
79
+
80
+ else
81
+ raise ArgumentError, "Instructions must be Hash, String, Symbol or nil"
82
+ end
83
+ end
84
+
85
+ ##### Action Templating #################################################
86
+
87
+ # Renders template for a prompt action or message.
88
+ #
89
+ # @param action_name [String, Symbol]
90
+ # @param locals [Hash]
91
+ # @return [String, nil]
92
+ def prompt_view_message(action_name, strict:, **locals)
93
+ view_render_template(action_name, strict:, **locals)
94
+ end
95
+
96
+ # Renders JSON schema from template or returns Hash directly.
97
+ #
98
+ # Schema templates are looked up as `{name}.json`:
99
+ # - When value is `true` or `nil`: looks for `{action_name}.json`
100
+ # - When value is a String/Symbol: looks for `{value}.json`
101
+ # - When value is a Hash: returns the Hash directly
102
+ #
103
+ # @param value [Hash, String, Symbol, Boolean, nil]
104
+ # @return [Hash, String, nil]
105
+ def prompt_view_schema(value)
106
+ case value
107
+ when Hash
108
+ value
109
+ when String, Symbol
110
+ JSON.parse(view_render_template(value, strict: true, formats: [ :json ]), symbolize_names: true)
111
+ when true, nil
112
+ JSON.parse(view_render_template(action_name, strict: true, formats: [ :json ]), symbolize_names: true)
113
+ end
114
+ end
115
+
116
+ # Renders template for embedding input.
117
+ #
118
+ # @param action_name [String, Symbol]
119
+ # @param locals [Hash]
120
+ # @return [String, nil]
121
+ def embed_view_input(action_name, **locals)
122
+ view_render_template(action_name, **locals)
123
+ end
124
+
125
+ private
126
+
127
+ ##### Shared Helpers ####################################################
128
+
129
+ # Renders a template if it exists in any supported ERB format.
130
+ #
131
+ # Templates are looked up using the prefixes defined in `_prefixes`:
132
+ # 1. `app/views/{agent_name}/` (e.g., `app/views/statements_agent/`)
133
+ # 2. `app/views/agents/{agent_without_suffix}/` (e.g., `app/views/agents/statements/`)
134
+ #
135
+ # @param template_name [String, Symbol] template file name without extension
136
+ # @param strict [Boolean] if true, raises error when template not found
137
+ # @param format [Symbol, nil] specific format to look for (e.g., :json, :html)
138
+ # @param locals [Hash] local variables passed to template
139
+ # @return [String, nil] nil if template not found and not strict
140
+ def view_render_template(template_name, strict: false, formats: nil, **locals)
141
+ options = { formats: }.compact
142
+
143
+ return if !strict && !lookup_context.exists?(template_name, _prefixes, false, [], **options)
144
+
145
+ template = lookup_context.find_template(template_name, _prefixes, false, [], **options)
146
+
147
+ render_to_string(template: template.virtual_path, locals:, layout: false).chomp.presence
148
+ end
149
+ end
150
+ end