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,97 @@
1
+ require_relative "_base_provider"
2
+
3
+ require_gem!(:openai, __FILE__)
4
+
5
+ require_relative "open_ai/_base"
6
+ require_relative "open_ai/chat_provider"
7
+ require_relative "open_ai/responses_provider"
8
+ require_relative "open_ai/embedding/_types"
9
+
10
+ module ActiveAgent
11
+ module Providers
12
+ # Router for OpenAI's API versions based on supported features.
13
+ #
14
+ # This provider acts as a thin wrapper that routes requests between different versions
15
+ # of OpenAI's API (Chat API and Responses API) depending on the features used in the prompt.
16
+ # It automatically selects the appropriate API version based on:
17
+ # - Explicit API version specification (+:api_version+ option)
18
+ # - Presence of audio content in the request
19
+ #
20
+ # @example Basic usage
21
+ # provider = ActiveAgent::Providers::OpenAIProvider.new(...)
22
+ # result = provider.generate
23
+ #
24
+ # @see https://platform.openai.com/docs/guides/migrate-to-responses
25
+ class OpenAIProvider < OpenAI::Base
26
+ # Returns the embedding request type for OpenAI.
27
+ #
28
+ # @return [ActiveModel::Type::Value] The OpenAI embedding request type
29
+ def self.embed_request_type
30
+ OpenAI::Embedding::RequestType.new
31
+ end
32
+
33
+ attr_internal :api_version
34
+ attr_internal :raw_options
35
+
36
+ # Initializes the OpenAI provider router.
37
+ #
38
+ # Since this layer is just routing based on API version, we want to wait
39
+ # to cast values into their types.
40
+ #
41
+ # @param kwargs [Hash] Configuration options for the provider
42
+ # @option kwargs [Symbol] :service The service name to validate
43
+ # @option kwargs [Symbol] :api_version The OpenAI API version to use (:chat or :responses)
44
+ def initialize(kwargs = {})
45
+ # For Routing Prompt APIs
46
+ self.api_version = kwargs.delete(:api_version)
47
+ self.raw_options = kwargs.deep_dup
48
+
49
+ super
50
+ end
51
+
52
+ # Generates a response by routing to the appropriate OpenAI API version.
53
+ #
54
+ # This method determines which API version to use based on the prompt context:
55
+ # - Uses Chat API if +api_version: :chat+ is specified or audio is present
56
+ # - Uses Responses API otherwise (default)
57
+ #
58
+ # @return [Object] The generation result from the selected API provider
59
+ #
60
+ # @see https://platform.openai.com/docs/guides/migrate-to-responses
61
+ def prompt
62
+ if api_version == :chat || context[:audio].present?
63
+ instrument("api_routing.provider.active_agent", api_type: :chat, api_version: api_version, has_audio: context[:audio].present?)
64
+ OpenAI::ChatProvider.new(raw_options).prompt
65
+ else # api_version == :responses || true
66
+ instrument("api_routing.provider.active_agent", api_type: :responses, api_version: api_version)
67
+ OpenAI::ResponsesProvider.new(raw_options).prompt
68
+ end
69
+ end
70
+
71
+ # Generates a preview by routing to the appropriate OpenAI API version.
72
+ #
73
+ # Routes to Chat API or Responses API using the same logic as {#prompt}.
74
+ #
75
+ # @return [String] markdown-formatted preview
76
+ # @see #prompt
77
+ def preview
78
+ if api_version == :chat || context[:audio].present?
79
+ OpenAI::ChatProvider.new(raw_options).preview
80
+ else # api_version == :responses || true
81
+ OpenAI::ResponsesProvider.new(raw_options).preview
82
+ end
83
+ end
84
+
85
+ protected
86
+
87
+ # Executes an embedding request via OpenAI's API.
88
+ #
89
+ # @param parameters [Hash] The embedding request parameters
90
+ # @return [Object] The embedding response from OpenAI
91
+ def api_embed_execute(parameters)
92
+ instrument("embeddings_request.provider.active_agent")
93
+ client.embeddings.create(**parameters).as_json.deep_symbolize_keys
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "requests/_types"
4
+
5
+ require_relative "request"
6
+ require_relative "options"
7
+
8
+ module ActiveAgent
9
+ module Providers
10
+ module OpenRouter
11
+ # Type for Request model
12
+ class RequestType < ActiveModel::Type::Value
13
+ def cast(value)
14
+ case value
15
+ when Request
16
+ value
17
+ when Hash
18
+ Request.new(**value.deep_symbolize_keys)
19
+ when nil
20
+ nil
21
+ else
22
+ raise ArgumentError, "Cannot cast #{value.class} to Request"
23
+ end
24
+ end
25
+
26
+ def serialize(value)
27
+ case value
28
+ when Request
29
+ value.serialize
30
+ when Hash
31
+ value
32
+ when nil
33
+ nil
34
+ else
35
+ raise ArgumentError, "Cannot serialize #{value.class}"
36
+ end
37
+ end
38
+
39
+ def deserialize(value)
40
+ cast(value)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../open_ai/options"
4
+ require_relative "requests/response_format"
5
+ require_relative "requests/prediction"
6
+ require_relative "requests/provider_preferences"
7
+
8
+ module ActiveAgent
9
+ module Providers
10
+ module OpenRouter
11
+ class Options < ActiveAgent::Providers::OpenAI::Options
12
+ attribute :base_url, :string, as: "https://openrouter.ai/api/v1"
13
+ attribute :app_name, :string, fallback: "ActiveAgent"
14
+ attribute :site_url, :string, fallback: "https://activeagents.ai/"
15
+
16
+ def initialize(kwargs = {})
17
+ kwargs = kwargs.deep_symbolize_keys if kwargs.respond_to?(:deep_symbolize_keys)
18
+
19
+ super(**deep_compact(kwargs.merge(
20
+ app_name: kwargs[:app_name] || resolve_app_name(kwargs),
21
+ site_url: kwargs[:site_url] || resolve_site_url(kwargs),
22
+ )))
23
+ end
24
+
25
+ def serialize
26
+ super.except(:app_name, :site_url)
27
+ end
28
+
29
+ # We fallback to ActiveAgent but allow empty strings to unset
30
+ def extra_headers
31
+ deep_compact(
32
+ "http-referer" => site_url.presence,
33
+ "x-title" => app_name.presence
34
+ )
35
+ end
36
+
37
+ private
38
+
39
+ def resolve_api_key(kwargs)
40
+ kwargs["api_key"] ||
41
+ ENV["OPENROUTER_API_KEY"] ||
42
+ ENV["OPEN_ROUTER_API_KEY"] ||
43
+ ENV["OPENROUTER_ACCESS_TOKEN"] ||
44
+ ENV["OPEN_ROUTER_ACCESS_TOKEN"]
45
+ end
46
+
47
+ # Not Used as Part of Open Router
48
+ def resolve_organization_id(kwargs) = nil
49
+ def resolve_project_id(kwargs) = nil
50
+
51
+ def resolve_app_name(kwargs)
52
+ if defined?(Rails) && Rails.application
53
+ Rails.application.class.name.split("::").first
54
+ end
55
+ end
56
+
57
+ def resolve_site_url(kwargs)
58
+ # First check ActiveAgent kwargs
59
+ return kwargs[:default_url_options][:host] if kwargs.dig(:default_url_options, :host)
60
+
61
+ # Then check Rails routes default_url_options
62
+ if defined?(Rails) && Rails.application&.routes&.default_url_options&.any?
63
+ host = Rails.application.routes.default_url_options[:host]
64
+ port = Rails.application.routes.default_url_options[:port]
65
+ protocol = Rails.application.routes.default_url_options[:protocol] || "https"
66
+
67
+ if host
68
+ url = "#{protocol}://#{host}"
69
+ url += ":#{port}" if port && port != 80 && port != 443
70
+ return url
71
+ end
72
+ end
73
+
74
+ # Finally check ActionMailer options as fallback
75
+ if defined?(Rails) && Rails.application&.config&.action_mailer&.default_url_options
76
+ options = Rails.application.config.action_mailer.default_url_options
77
+ host = options[:host]
78
+ port = options[:port]
79
+ protocol = options[:protocol] || "https"
80
+
81
+ if host
82
+ url = "#{protocol}://#{host}"
83
+ url += ":#{port}" if port && port != 80 && port != 443
84
+ return url
85
+ end
86
+ end
87
+
88
+ nil
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../open_ai/_types"
4
+ require_relative "requests/_types"
5
+
6
+ module ActiveAgent
7
+ module Providers
8
+ module OpenRouter
9
+ class Request < OpenAI::Chat::Request
10
+ # Prompting Options
11
+ attribute :model, :string, fallback: "openrouter/auto"
12
+ attribute :response_format, Requests::ResponseFormatType.new
13
+ attribute :max_tokens, :integer
14
+ attribute :stop # Can be string or array
15
+
16
+ # Messages array (required)
17
+ attribute :messages, Requests::Messages::MessagesType.new
18
+
19
+ # LLM Parameters
20
+ attribute :seed, :integer
21
+ attribute :top_p, :float
22
+ attribute :top_k, :integer
23
+ attribute :frequency_penalty, :float
24
+ attribute :presence_penalty, :float
25
+ attribute :repetition_penalty, :float
26
+ attribute :top_logprobs, :integer
27
+ attribute :min_p, :float
28
+ attribute :top_a, :float
29
+ attribute :logit_bias # Hash of token_id => bias value
30
+
31
+ # Tool calling (inherited from OpenAI but explicitly documented)
32
+ # attribute :tools, :json
33
+ # attribute :tool_choice, :json
34
+
35
+ # Predicted outputs
36
+ attribute :prediction, Requests::PredictionType.new
37
+
38
+ # OpenRouter-specific parameters
39
+ attribute :transforms, default: -> { [] } # Array of strings
40
+ attribute :models, default: -> { [] } # Array of model strings for fallback
41
+ attribute :route, :string, default: "fallback"
42
+ attribute :provider, Requests::ProviderPreferencesType.new, default: {}
43
+ attribute :user, :string # Stable identifier for end-users
44
+ attribute :plugins, Requests::PluginsType.new # Array of plugin configurations (e.g., file-parser for PDFs)
45
+
46
+ # Validations for parameters with specific ranges
47
+ validates :max_tokens, numericality: { greater_than_or_equal_to: 1 }, allow_nil: true
48
+ validates :top_p, numericality: { greater_than: 0, less_than_or_equal_to: 1 }, allow_nil: true
49
+ validates :top_k, numericality: { greater_than_or_equal_to: 1 }, allow_nil: true
50
+ validates :frequency_penalty, numericality: { greater_than_or_equal_to: -2, less_than_or_equal_to: 2 }, allow_nil: true
51
+ validates :presence_penalty, numericality: { greater_than_or_equal_to: -2, less_than_or_equal_to: 2 }, allow_nil: true
52
+ validates :repetition_penalty, numericality: { greater_than: 0, less_than_or_equal_to: 2 }, allow_nil: true
53
+ validates :min_p, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }, allow_nil: true
54
+ validates :top_a, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }, allow_nil: true
55
+ validates :route, inclusion: { in: [ "fallback" ] }, allow_nil: true
56
+
57
+ # Backwards Compatibility
58
+ delegate_attributes :data_collection, :enable_fallbacks, :sort, :ignore, :only, :quantizations, :max_price, to: :provider
59
+ alias_attribute :fallback_models, :models
60
+
61
+ # Common Format Compatability
62
+ def messages=(value)
63
+ case value
64
+ when Array
65
+ super((messages || []) | value)
66
+ else
67
+ super((messages || []) | [ value ])
68
+ end
69
+ end
70
+
71
+ # Common Format Compatability
72
+ def response_format=(value)
73
+ # If we are doing structured output, we need to ensure that we route to models that support it.
74
+ if %i[json_object json_schema].include?(value[:type].to_sym)
75
+ self.provider.require_parameters = true
76
+ end
77
+
78
+ super(value)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "messages/_types"
4
+ require_relative "provider_preferences/_types"
5
+ require_relative "plugins/_types"
6
+
7
+ require_relative "message"
8
+ require_relative "prediction"
9
+ require_relative "provider_preferences"
10
+ require_relative "response_format"
11
+ require_relative "plugin"
12
+
13
+ module ActiveAgent
14
+ module Providers
15
+ module OpenRouter
16
+ module Requests
17
+ # Type for MaxPrice
18
+ class MaxPriceType < ActiveModel::Type::Value
19
+ def cast(value)
20
+ case value
21
+ when MaxPrice
22
+ value
23
+ when Hash
24
+ MaxPrice.new(**value.deep_symbolize_keys)
25
+ when nil
26
+ nil
27
+ else
28
+ raise ArgumentError, "Cannot cast #{value.class} to MaxPrice"
29
+ end
30
+ end
31
+
32
+ def serialize(value)
33
+ case value
34
+ when MaxPrice
35
+ value.serialize
36
+ when Hash
37
+ value
38
+ when nil
39
+ nil
40
+ else
41
+ raise ArgumentError, "Cannot serialize #{value.class}"
42
+ end
43
+ end
44
+
45
+ def deserialize(value)
46
+ cast(value)
47
+ end
48
+ end
49
+
50
+ # Type for Prediction
51
+ class PredictionType < ActiveModel::Type::Value
52
+ def cast(value)
53
+ case value
54
+ when Prediction
55
+ value
56
+ when Hash
57
+ Prediction.new(**value.deep_symbolize_keys)
58
+ when nil
59
+ nil
60
+ else
61
+ raise ArgumentError, "Cannot cast #{value.class} to Prediction"
62
+ end
63
+ end
64
+
65
+ def serialize(value)
66
+ case value
67
+ when Prediction
68
+ value.serialize
69
+ when Hash
70
+ value
71
+ when nil
72
+ nil
73
+ else
74
+ raise ArgumentError, "Cannot serialize #{value.class}"
75
+ end
76
+ end
77
+
78
+ def deserialize(value)
79
+ cast(value)
80
+ end
81
+ end
82
+
83
+ # Type for ProviderPreferences
84
+ class ProviderPreferencesType < ActiveModel::Type::Value
85
+ def cast(value)
86
+ case value
87
+ when ProviderPreferences
88
+ value
89
+ when Hash
90
+ ProviderPreferences.new(**value.deep_symbolize_keys)
91
+ when nil
92
+ nil
93
+ else
94
+ raise ArgumentError, "Cannot cast #{value.class} to ProviderPreferences"
95
+ end
96
+ end
97
+
98
+ def serialize(value)
99
+ case value
100
+ when ProviderPreferences
101
+ value.serialize
102
+ when Hash
103
+ value
104
+ when nil
105
+ nil
106
+ else
107
+ raise ArgumentError, "Cannot serialize #{value.class}"
108
+ end
109
+ end
110
+
111
+ def deserialize(value)
112
+ cast(value)
113
+ end
114
+ end
115
+
116
+ # Type for ResponseFormat
117
+ class ResponseFormatType < ActiveModel::Type::Value
118
+ def cast(value)
119
+ case value
120
+ when ResponseFormat
121
+ value
122
+ when Hash
123
+ ResponseFormat.new(**value.deep_symbolize_keys)
124
+ when nil
125
+ nil
126
+ else
127
+ raise ArgumentError, "Cannot cast #{value.class} to ResponseFormat"
128
+ end
129
+ end
130
+
131
+ def serialize(value)
132
+ case value
133
+ when ResponseFormat
134
+ value.serialize
135
+ when Hash
136
+ value
137
+ when nil
138
+ nil
139
+ else
140
+ raise ArgumentError, "Cannot serialize #{value.class}"
141
+ end
142
+ end
143
+
144
+ def deserialize(value)
145
+ cast(value)
146
+ end
147
+ end
148
+
149
+ # Type for Plugins (array of Plugin objects)
150
+ class PluginsType < ActiveModel::Type::Value
151
+ def cast(value)
152
+ case value
153
+ when Array
154
+ value.map do |item|
155
+ case item
156
+ when Plugin
157
+ item
158
+ when Hash
159
+ Plugin.new(**item.deep_symbolize_keys)
160
+ else
161
+ raise ArgumentError, "Cannot cast #{item.class} to Plugin"
162
+ end
163
+ end
164
+ when nil
165
+ nil
166
+ else
167
+ raise ArgumentError, "Cannot cast #{value.class} to Array of Plugins"
168
+ end
169
+ end
170
+
171
+ def serialize(value)
172
+ case value
173
+ when Array
174
+ value.map do |item|
175
+ case item
176
+ when Plugin
177
+ item.serialize
178
+ when Hash
179
+ item
180
+ else
181
+ raise ArgumentError, "Cannot serialize #{item.class}"
182
+ end
183
+ end
184
+ when nil
185
+ nil
186
+ else
187
+ raise ArgumentError, "Cannot serialize #{value.class}"
188
+ end
189
+ end
190
+
191
+ def deserialize(value)
192
+ cast(value)
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1 @@
1
+ require_relative "messages/assistant"
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_agent/providers/open_ai/chat/requests/messages/_types"
4
+
5
+ require_relative "assistant"
6
+ require_relative "user"
7
+
8
+ module ActiveAgent
9
+ module Providers
10
+ module OpenRouter
11
+ module Requests
12
+ module Messages
13
+ # Type for Messages array - uses OpenRouter's MessageType
14
+ class MessagesType < OpenAI::Chat::Requests::Messages::MessagesType
15
+ def initialize
16
+ super
17
+ @message_type = MessageType.new
18
+ end
19
+ end
20
+
21
+ class MessageType < OpenAI::Chat::Requests::Messages::MessageType
22
+ def cast(value)
23
+ case value
24
+ when OpenAI::Chat::Requests::Messages::Base
25
+ value
26
+ when String
27
+ User.new(content: value)
28
+ when Hash
29
+ hash = value.deep_symbolize_keys
30
+ role = hash[:role]&.to_sym
31
+
32
+ case role
33
+ when :developer
34
+ OpenAI::Chat::Requests::Messages::Developer.new(**hash)
35
+ when :system
36
+ OpenAI::Chat::Requests::Messages::System.new(**hash)
37
+ when :user, nil
38
+ User.new(**hash)
39
+ when :assistant
40
+ Assistant.new(**hash)
41
+ when :tool
42
+ OpenAI::Chat::Requests::Messages::Tool.new(**hash)
43
+ when :function
44
+ OpenAI::Chat::Requests::Messages::Function.new(**hash)
45
+ else
46
+ raise ArgumentError, "Unknown message role: #{role.inspect}"
47
+ end
48
+ when nil
49
+ nil
50
+ else
51
+ raise ArgumentError, "Cannot cast #{value.class} to Message (expected Base, String, Hash, or nil)"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ module Providers
5
+ module OpenRouter
6
+ module Requests
7
+ module Messages
8
+ # Assistant message for OpenRouter API.
9
+ #
10
+ # Extends OpenAI's assistant message with OpenRouter-specific behavior.
11
+ # Drops reasoning fields during message reconstruction since they're not
12
+ # part of the standard request format.
13
+ class Assistant < OpenAI::Chat::Requests::Messages::Assistant
14
+ drop_attributes :reasoning, :reasoning_details
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_agent/providers/open_ai/chat/requests/messages/content/_types"
4
+ require_relative "file"
5
+
6
+ module ActiveAgent
7
+ module Providers
8
+ module OpenRouter
9
+ module Requests
10
+ module Messages
11
+ module Content
12
+ # Type for handling content (string or array of content parts) in OpenRouter.
13
+ #
14
+ # Extends OpenAI's ContentsType to use OpenRouter's ContentType which
15
+ # handles files differently (preserves data URI prefix).
16
+ class ContentsType < OpenAI::Chat::Requests::Messages::Content::ContentsType
17
+ def initialize
18
+ super
19
+ @content_type = ContentType.new
20
+ end
21
+ end
22
+
23
+ # Type for individual content items in OpenRouter.
24
+ #
25
+ # Uses OpenRouter's File class for file content which preserves
26
+ # the data URI prefix that OpenAI strips.
27
+ class ContentType < ActiveModel::Type::Value
28
+ def cast(value)
29
+ case value
30
+ when OpenAI::Chat::Requests::Messages::Content::Base
31
+ value
32
+ when Hash
33
+ hash = value.deep_symbolize_keys
34
+ type = hash[:type]&.to_sym
35
+
36
+ case type
37
+ when :text
38
+ OpenAI::Chat::Requests::Messages::Content::Text.new(**hash)
39
+ when :image_url
40
+ OpenAI::Chat::Requests::Messages::Content::Image.new(**hash)
41
+ when :input_audio
42
+ OpenAI::Chat::Requests::Messages::Content::Audio.new(**hash)
43
+ when :file
44
+ # Use OpenRouter's File class instead of OpenAI's
45
+ File.new(**hash)
46
+ when :refusal
47
+ OpenAI::Chat::Requests::Messages::Content::Refusal.new(**hash)
48
+ when nil
49
+ # When type is nil, check for specific content keys to infer type
50
+ if hash.key?(:text)
51
+ OpenAI::Chat::Requests::Messages::Content::Text.new(**hash)
52
+ elsif hash.key?(:image)
53
+ OpenAI::Chat::Requests::Messages::Content::Image.new(**hash.merge(image_url: hash.delete(:image)))
54
+ elsif hash.key?(:document)
55
+ # Use OpenRouter's File class for document content
56
+ File.new(**hash.merge(file: hash.delete(:document)))
57
+ else
58
+ raise ArgumentError, "Cannot determine content type from hash keys: #{hash.keys.inspect}"
59
+ end
60
+ else
61
+ raise ArgumentError, "Unknown content type: #{type.inspect}"
62
+ end
63
+ when String
64
+ # Plain text string becomes text content
65
+ OpenAI::Chat::Requests::Messages::Content::Text.new(text: value)
66
+ when nil
67
+ nil
68
+ else
69
+ raise ArgumentError, "Cannot cast #{value.class} to Content (expected Base, Hash, String, or nil)"
70
+ end
71
+ end
72
+
73
+ def serialize(value)
74
+ case value
75
+ when OpenAI::Chat::Requests::Messages::Content::Base
76
+ value.serialize
77
+ when Hash
78
+ value
79
+ when String
80
+ { type: "text", text: value }
81
+ when nil
82
+ nil
83
+ else
84
+ raise ArgumentError, "Cannot serialize #{value.class} as Content"
85
+ end
86
+ end
87
+
88
+ def deserialize(value)
89
+ cast(value)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end