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