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,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Messages
|
|
9
|
+
class Base < Common::BaseModel
|
|
10
|
+
attribute :role, :string
|
|
11
|
+
|
|
12
|
+
validates :role, presence: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Messages
|
|
9
|
+
# System message - provides instructions and context to the AI
|
|
10
|
+
class System < Base
|
|
11
|
+
attribute :role, :string, as: "system"
|
|
12
|
+
attribute :content, :string # Text content
|
|
13
|
+
attribute :name, :string # Optional name for the system message
|
|
14
|
+
|
|
15
|
+
validates :content, presence: true
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Messages
|
|
9
|
+
# Tool message - messages containing tool call results
|
|
10
|
+
class Tool < Base
|
|
11
|
+
attribute :role, :string, as: "tool"
|
|
12
|
+
attribute :content, :string # Tool result content
|
|
13
|
+
attribute :tool_call_id, :string # ID of the tool call this is responding to
|
|
14
|
+
attribute :name, :string # Optional name of the tool
|
|
15
|
+
|
|
16
|
+
validates :content, presence: true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Messages
|
|
9
|
+
# Represents a message sent by the user in a conversation
|
|
10
|
+
class User < Base
|
|
11
|
+
attribute :role, :string, as: "user"
|
|
12
|
+
attribute :content, :string
|
|
13
|
+
attribute :name, :string
|
|
14
|
+
|
|
15
|
+
validates :content, presence: true
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
module Providers
|
|
5
|
+
module Common
|
|
6
|
+
# BaseModel provides a foundation for structured data models with compressed serialization support.
|
|
7
|
+
#
|
|
8
|
+
# This class extends ActiveModel functionality to provide:
|
|
9
|
+
# - Attribute definition with default values
|
|
10
|
+
# - Compressed hash serialization (excludes default values)
|
|
11
|
+
# - Required attribute tracking
|
|
12
|
+
# - Deep compaction of nested structures
|
|
13
|
+
#
|
|
14
|
+
# == Example
|
|
15
|
+
#
|
|
16
|
+
# class Message < BaseModel
|
|
17
|
+
# attribute :role, :string, as: "user"
|
|
18
|
+
# attribute :type, :string, fallback: "plain/text"
|
|
19
|
+
# attribute :content, :string
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# message = Message.new(content: "Hello")
|
|
23
|
+
# message.to_h #=> { role: "user", type: "plain/text", content: "Hello" }
|
|
24
|
+
# message.serialize #=> { role: "user", type: "plain/text", content: "Hello" }
|
|
25
|
+
class BaseModel
|
|
26
|
+
include ActiveModel::Model
|
|
27
|
+
include ActiveModel::Attributes
|
|
28
|
+
|
|
29
|
+
# Returns the set of required attribute names that must be included in compressed output.
|
|
30
|
+
#
|
|
31
|
+
# Required attributes are those defined with the +as+ option, which establishes
|
|
32
|
+
# a default value that should always be serialized.
|
|
33
|
+
#
|
|
34
|
+
# @return [Set<String>] set of required attribute names
|
|
35
|
+
def self.required_attributes
|
|
36
|
+
@required_attributes ||= Set.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Ensures subclasses get their own required_attributes set.
|
|
40
|
+
#
|
|
41
|
+
# @param subclass [Class] the inheriting class
|
|
42
|
+
# @return [void]
|
|
43
|
+
def self.inherited(subclass)
|
|
44
|
+
super
|
|
45
|
+
subclass.instance_variable_set(:@required_attributes, required_attributes.dup)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Defines an attribute on the model with special handling for default values.
|
|
49
|
+
#
|
|
50
|
+
# @param name [Symbol, String] the name of the attribute
|
|
51
|
+
# @param type [Class, nil] the type of the attribute (optional)
|
|
52
|
+
# @param options [Hash] additional options for the attribute
|
|
53
|
+
# @option options [Object] :as A default value that makes the attribute read-only.
|
|
54
|
+
# When set, attempts to assign a different value will raise an ArgumentError.
|
|
55
|
+
# This attribute will be included in the compressed hash representation.
|
|
56
|
+
# @option options [Object] :fallback A default value for the attribute.
|
|
57
|
+
# This attribute will be included in the compressed hash representation.
|
|
58
|
+
#
|
|
59
|
+
# @raise [ArgumentError] if attempting to set a value different from the :as default
|
|
60
|
+
#
|
|
61
|
+
# @example Define a read-only attribute with a default value
|
|
62
|
+
# attribute :role, :string, as: "user"
|
|
63
|
+
#
|
|
64
|
+
# @example Define an attribute with a fallback value
|
|
65
|
+
# attribute :temperature, :float, fallback: 0.7
|
|
66
|
+
#
|
|
67
|
+
# @example Define a regular attribute
|
|
68
|
+
# attribute :messages, :array
|
|
69
|
+
def self.attribute(name, type = nil, **options)
|
|
70
|
+
if options.key?(:as)
|
|
71
|
+
default_value = options.delete(:as)
|
|
72
|
+
super(name, type, default: default_value, **options)
|
|
73
|
+
|
|
74
|
+
# Track this attribute as required (must be included in compressed hash)
|
|
75
|
+
required_attributes << name.to_s
|
|
76
|
+
|
|
77
|
+
define_method("#{name}=") do |value|
|
|
78
|
+
normalized_value = value.is_a?(String) ? value.to_sym : value
|
|
79
|
+
normalized_default = default_value.is_a?(String) ? default_value.to_sym : default_value
|
|
80
|
+
|
|
81
|
+
next if normalized_value == normalized_default
|
|
82
|
+
|
|
83
|
+
raise ArgumentError, "Cannot set '#{name}' attribute (read-only with default value)"
|
|
84
|
+
end
|
|
85
|
+
elsif options.key?(:fallback)
|
|
86
|
+
default_value = options.delete(:fallback)
|
|
87
|
+
super(name, type, default: default_value, **options)
|
|
88
|
+
|
|
89
|
+
# Track this attribute as required (must be included in compressed hash)
|
|
90
|
+
required_attributes << name.to_s
|
|
91
|
+
else
|
|
92
|
+
super(name, type, **options)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Delegates attribute accessors to another object.
|
|
97
|
+
#
|
|
98
|
+
# Creates getter and setter methods that forward to the specified target object.
|
|
99
|
+
# If the target is nil when setting, an empty hash is initialized.
|
|
100
|
+
#
|
|
101
|
+
# @param attributes [Array<Symbol>] attribute names to delegate
|
|
102
|
+
# @param to [Symbol] the target method/attribute name
|
|
103
|
+
#
|
|
104
|
+
# @example
|
|
105
|
+
# delegate_attributes :temperature, :max_tokens, to: :options
|
|
106
|
+
def self.delegate_attributes(*attributes, to:)
|
|
107
|
+
attributes.each do |attribute|
|
|
108
|
+
define_method(attribute) do
|
|
109
|
+
public_send(to)&.public_send(attribute)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
define_method("#{attribute}=") do |value|
|
|
113
|
+
public_send("#{to}=", {}) if public_send(to).nil?
|
|
114
|
+
|
|
115
|
+
public_send(to).public_send("#{attribute}=", value)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Drops specified attributes by defining no-op setters.
|
|
121
|
+
#
|
|
122
|
+
# This is useful when converting between providers that support different attributes
|
|
123
|
+
# or when dropping attributes during message response to request construction.
|
|
124
|
+
# The attributes can still be read if defined elsewhere, but setting them has no effect.
|
|
125
|
+
#
|
|
126
|
+
# @param attributes [Array<Symbol>] attribute names to drop
|
|
127
|
+
# @return [void]
|
|
128
|
+
#
|
|
129
|
+
# @example
|
|
130
|
+
# drop_attributes :metadata, :extra_info
|
|
131
|
+
def self.drop_attributes(*attributes)
|
|
132
|
+
attributes.each do |attribute|
|
|
133
|
+
define_method("#{attribute}=") do |value|
|
|
134
|
+
# No-Op: Drop the value
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Returns all attribute keys including aliases.
|
|
140
|
+
#
|
|
141
|
+
# Combines both the main attribute type keys and any attribute aliases,
|
|
142
|
+
# ensuring all possible attribute names are represented as symbols.
|
|
143
|
+
#
|
|
144
|
+
# @return [Array<Symbol>] array of all attribute keys
|
|
145
|
+
def self.keys
|
|
146
|
+
(attribute_types.keys.map(&:to_sym) | attribute_aliases.keys.map(&:to_sym))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Initializes a new instance with the given attributes.
|
|
150
|
+
#
|
|
151
|
+
# Attributes can be provided as a hash. Hash keys are sorted to prioritize nested
|
|
152
|
+
# objects during initialization for backwards compatibility. A special internal key
|
|
153
|
+
# `__default_values` can be passed to get an instance with only default values
|
|
154
|
+
# without any overrides.
|
|
155
|
+
#
|
|
156
|
+
# @param kwargs [Hash] attributes to initialize the instance with
|
|
157
|
+
# @return [BaseModel] the initialized instance
|
|
158
|
+
#
|
|
159
|
+
# @example
|
|
160
|
+
# Message.new(role: "user", content: "Hello")
|
|
161
|
+
def initialize(kwargs = {})
|
|
162
|
+
# To allow us to get a list of attribute defaults without initialized overrides
|
|
163
|
+
return super(nil) if kwargs.key?(:'__default_values')
|
|
164
|
+
|
|
165
|
+
# Backwards Compatibility: This sorts object construction to the top to protect the assignment
|
|
166
|
+
# of backward compatibility assignments.
|
|
167
|
+
kwargs = kwargs.sort_by { |k, v| v.is_a?(Hash) ? 0 : 1 }.to_h if kwargs.is_a?(Hash)
|
|
168
|
+
|
|
169
|
+
super(kwargs)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Merges the given attributes into the current instance.
|
|
173
|
+
#
|
|
174
|
+
# Only attributes with corresponding setter methods are updated.
|
|
175
|
+
# Keys are symbolized before merging.
|
|
176
|
+
#
|
|
177
|
+
# @param kwargs [Hash] attribute keyword arguments to merge
|
|
178
|
+
# @return [BaseModel] self for method chaining
|
|
179
|
+
def merge!(kwargs = {})
|
|
180
|
+
kwargs.deep_symbolize_keys.each do |key, value|
|
|
181
|
+
public_send("#{key}=", value) if respond_to?("#{key}=")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
self
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Recursively removes nil values and empty collections from a hash.
|
|
188
|
+
#
|
|
189
|
+
# Nested hashes and arrays are processed recursively. Empty hashes and
|
|
190
|
+
# arrays after compaction are also removed.
|
|
191
|
+
#
|
|
192
|
+
# @param kwargs [Hash] hash to compact
|
|
193
|
+
# @return [Hash] compacted hash with nil values and empty collections removed
|
|
194
|
+
#
|
|
195
|
+
# @example
|
|
196
|
+
# deep_compact({ a: 1, b: nil, c: { d: nil, e: 2 } })
|
|
197
|
+
# #=> { a: 1, c: { e: 2 } }
|
|
198
|
+
def deep_compact(kwargs = {})
|
|
199
|
+
kwargs.each_with_object({}) do |(key, value), result|
|
|
200
|
+
compacted_value = case value
|
|
201
|
+
when Hash
|
|
202
|
+
deep_compacted = deep_compact(value)
|
|
203
|
+
deep_compacted unless deep_compacted.empty?
|
|
204
|
+
when Array
|
|
205
|
+
compacted_array = value.map { |v| v.is_a?(Hash) ? deep_compact(v) : v }.compact
|
|
206
|
+
compacted_array unless compacted_array.empty?
|
|
207
|
+
else
|
|
208
|
+
value
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
result[key] = compacted_value unless compacted_value.nil?
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Converts the model to a hash representation.
|
|
216
|
+
#
|
|
217
|
+
# Recursively converts nested BaseModel instances and arrays to hashes.
|
|
218
|
+
# Nil values and empty collections are removed via deep_compact.
|
|
219
|
+
#
|
|
220
|
+
# @return [Hash] hash representation of all attributes
|
|
221
|
+
#
|
|
222
|
+
# @example
|
|
223
|
+
# message.to_hash
|
|
224
|
+
# #=> { role: "user", content: "Hello", metadata: { id: 1 } }
|
|
225
|
+
def to_hash
|
|
226
|
+
deep_compact(attribute_names.each_with_object({}) do |name, hash|
|
|
227
|
+
value = public_send(name)
|
|
228
|
+
|
|
229
|
+
hash[name.to_sym] = case value
|
|
230
|
+
when BaseModel then value.to_hash
|
|
231
|
+
when Array then value.map { _1.is_a?(BaseModel) ? _1.to_hash : _1 }
|
|
232
|
+
else
|
|
233
|
+
value
|
|
234
|
+
end
|
|
235
|
+
end)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Alias for {#to_hash}.
|
|
239
|
+
#
|
|
240
|
+
# @return [Hash] hash representation of all attributes
|
|
241
|
+
# @see #to_hash
|
|
242
|
+
def to_h = to_hash
|
|
243
|
+
|
|
244
|
+
# Creates a deep duplicate of the model.
|
|
245
|
+
#
|
|
246
|
+
# Duplicates the model instance and recursively duplicates any array or hash attributes
|
|
247
|
+
# to ensure complete independence from the original object.
|
|
248
|
+
#
|
|
249
|
+
# @return [BaseModel] deep duplicate of the model
|
|
250
|
+
def deep_dup
|
|
251
|
+
dup.tap do |duplicated|
|
|
252
|
+
attribute_names.each do |name|
|
|
253
|
+
value = public_send(name)
|
|
254
|
+
next if value.nil?
|
|
255
|
+
|
|
256
|
+
duplicated.public_send("#{name}=", case value
|
|
257
|
+
when Array
|
|
258
|
+
value.map { |v| v.respond_to?(:deep_dup) ? v.deep_dup : v.dup rescue v }
|
|
259
|
+
when Hash
|
|
260
|
+
value.deep_dup
|
|
261
|
+
when BaseModel
|
|
262
|
+
value.deep_dup
|
|
263
|
+
else
|
|
264
|
+
value.dup rescue value
|
|
265
|
+
end)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Serializes the model using attribute type serializers.
|
|
271
|
+
#
|
|
272
|
+
# Iterates through each attribute and uses its ActiveModel::Type serializer
|
|
273
|
+
# to convert the value to its serialized form. Only non-default values are included,
|
|
274
|
+
# except for required attributes (those defined with `:as` or `:fallback` options).
|
|
275
|
+
# This provides a compressed serialization that respects custom type logic.
|
|
276
|
+
#
|
|
277
|
+
# @return [Hash] serialized representation with non-default and required attributes
|
|
278
|
+
#
|
|
279
|
+
# @example
|
|
280
|
+
# message = Message.new(role: "user", content: "Hello")
|
|
281
|
+
# message.serialize #=> { role: "user", content: "Hello" }
|
|
282
|
+
def serialize
|
|
283
|
+
default_values = self.class.new(__default_values: true).attributes
|
|
284
|
+
required_attrs = self.class.required_attributes
|
|
285
|
+
|
|
286
|
+
deep_compact(attribute_names.each_with_object({}) do |name, hash|
|
|
287
|
+
value = public_send(name)
|
|
288
|
+
|
|
289
|
+
# Always include required attributes (those defined with 'as' option)
|
|
290
|
+
# or attributes that differ from their default value
|
|
291
|
+
next if value == default_values[name] && !required_attrs.include?(name)
|
|
292
|
+
|
|
293
|
+
# Use the attribute's type serializer
|
|
294
|
+
attr_type = self.class.attribute_types[name]
|
|
295
|
+
hash[name.to_sym] = attr_type.serialize(value)
|
|
296
|
+
end)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Returns a string representation for inspection.
|
|
300
|
+
#
|
|
301
|
+
# Provides a readable view of the model showing the class name and non-default attributes
|
|
302
|
+
# in a format similar to standard Ruby object inspection.
|
|
303
|
+
#
|
|
304
|
+
# @return [String] formatted string representation
|
|
305
|
+
# @see #serialize
|
|
306
|
+
#
|
|
307
|
+
# @example
|
|
308
|
+
# message = Message.new(role: "user", content: "Hello")
|
|
309
|
+
# message.inspect
|
|
310
|
+
# #=> "#<Message role: \"user\", content: \"Hello\">"
|
|
311
|
+
def inspect
|
|
312
|
+
attrs = JSON.pretty_generate(serialize, {
|
|
313
|
+
space: " ",
|
|
314
|
+
indent: " ",
|
|
315
|
+
object_nl: "\n",
|
|
316
|
+
array_nl: "\n"
|
|
317
|
+
}).lines.drop(1).join.chomp.sub(/\}\z/, "").strip
|
|
318
|
+
|
|
319
|
+
return "#<#{self.class.name}>" if attrs.empty?
|
|
320
|
+
|
|
321
|
+
"#<#{self.class.name} {\n #{attrs}\n}>"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# @see #inspect
|
|
325
|
+
alias_method :to_s, :inspect
|
|
326
|
+
|
|
327
|
+
# Compares two models based on their serialized representations.
|
|
328
|
+
#
|
|
329
|
+
# Uses the serialized hash to compare models, allowing for sorting and equality
|
|
330
|
+
# comparisons based on attribute values rather than object identity.
|
|
331
|
+
#
|
|
332
|
+
# @param other [BaseModel] the model to compare against
|
|
333
|
+
# @return [Integer, nil] -1, 0, 1, or nil if not comparable
|
|
334
|
+
#
|
|
335
|
+
# @example
|
|
336
|
+
# model1 = Message.new(content: "A")
|
|
337
|
+
# model2 = Message.new(content: "B")
|
|
338
|
+
# model1 <=> model2 #=> -1
|
|
339
|
+
def <=>(other)
|
|
340
|
+
serialize <=> other&.serialize
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Compares equality based on serialized representation.
|
|
344
|
+
#
|
|
345
|
+
# Two models are equal if their serialized hashes are equal, regardless
|
|
346
|
+
# of object identity. This allows value-based equality comparisons.
|
|
347
|
+
#
|
|
348
|
+
# @param other [BaseModel] the model to compare against
|
|
349
|
+
# @return [Boolean]
|
|
350
|
+
#
|
|
351
|
+
# @example
|
|
352
|
+
# model1 = Message.new(content: "Hello")
|
|
353
|
+
# model2 = Message.new(content: "Hello")
|
|
354
|
+
# model1 == model2 #=> true
|
|
355
|
+
def ==(other)
|
|
356
|
+
serialize == other&.serialize
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "responses/prompt"
|
|
4
|
+
require_relative "responses/embed"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module Common
|
|
9
|
+
PromptResponse = Responses::Prompt
|
|
10
|
+
EmbedResponse = Responses::Embed
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../messages/_types"
|
|
4
|
+
|
|
5
|
+
require_relative "format"
|
|
6
|
+
|
|
7
|
+
module ActiveAgent
|
|
8
|
+
module Providers
|
|
9
|
+
module Common
|
|
10
|
+
module Responses
|
|
11
|
+
module Types
|
|
12
|
+
# Type for Messages array - delegates to the shared common messages type
|
|
13
|
+
class MessagesType < Common::Messages::Types::MessagesType
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class FormatType < ActiveModel::Type::Value
|
|
17
|
+
def cast(value)
|
|
18
|
+
case value
|
|
19
|
+
when BaseModel
|
|
20
|
+
Responses::Format.new(**value.serialize)
|
|
21
|
+
when Hash
|
|
22
|
+
Responses::Format.new(**value.deep_symbolize_keys)
|
|
23
|
+
when nil
|
|
24
|
+
nil
|
|
25
|
+
else
|
|
26
|
+
raise ArgumentError, "Cannot cast #{value.class} to Format"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def serialize(value)
|
|
31
|
+
case value
|
|
32
|
+
when Format
|
|
33
|
+
value.serialize
|
|
34
|
+
when Hash
|
|
35
|
+
value
|
|
36
|
+
when nil
|
|
37
|
+
nil
|
|
38
|
+
else
|
|
39
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def deserialize(value)
|
|
44
|
+
cast(value)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Responses
|
|
9
|
+
# Base response model for provider responses.
|
|
10
|
+
#
|
|
11
|
+
# This class represents the standard response structure from AI providers
|
|
12
|
+
# across different services (OpenAI, Anthropic, etc.). It provides a unified
|
|
13
|
+
# interface for accessing response data, usage statistics, and request context.
|
|
14
|
+
#
|
|
15
|
+
# @abstract Subclass and override {#usage} if provider uses non-standard format
|
|
16
|
+
#
|
|
17
|
+
# @note This is a base class. Use specialized subclasses for specific response types:
|
|
18
|
+
# - {Prompt} for conversational/completion responses with messages
|
|
19
|
+
# - {Embed} for embedding responses with vector data
|
|
20
|
+
#
|
|
21
|
+
# @example Accessing response data
|
|
22
|
+
# response = agent.prompt.generate_now
|
|
23
|
+
# response.success? #=> true
|
|
24
|
+
# response.usage #=> { "prompt_tokens" => 10, "completion_tokens" => 20 }
|
|
25
|
+
# response.total_tokens #=> 30
|
|
26
|
+
#
|
|
27
|
+
# @example Inspecting raw provider data
|
|
28
|
+
# response.raw_request #=> { "model" => "gpt-4", "messages" => [...] }
|
|
29
|
+
# response.raw_response #=> { "id" => "chatcmpl-...", "choices" => [...] }
|
|
30
|
+
#
|
|
31
|
+
# @see Prompt
|
|
32
|
+
# @see Embed
|
|
33
|
+
# @see BaseModel
|
|
34
|
+
class Base < BaseModel
|
|
35
|
+
# @!attribute [r] context
|
|
36
|
+
# The original context that was sent to the provider.
|
|
37
|
+
#
|
|
38
|
+
# Contains structured information about the request including instructions,
|
|
39
|
+
# messages, tools, and other configuration passed to the LLM.
|
|
40
|
+
#
|
|
41
|
+
# @return [Hash] the request context
|
|
42
|
+
attribute :context, writable: false
|
|
43
|
+
|
|
44
|
+
# @!attribute [r] raw_request
|
|
45
|
+
# The most recent request in provider-specific format.
|
|
46
|
+
#
|
|
47
|
+
# Contains the actual API request payload sent to the provider,
|
|
48
|
+
# useful for debugging and logging.
|
|
49
|
+
#
|
|
50
|
+
# @return [Hash] the provider-formatted request
|
|
51
|
+
attribute :raw_request, writable: false
|
|
52
|
+
|
|
53
|
+
# @!attribute [r] raw_response
|
|
54
|
+
# The most recent response in provider-specific format.
|
|
55
|
+
#
|
|
56
|
+
# Contains the raw API response from the provider, including all
|
|
57
|
+
# metadata, usage stats, and provider-specific fields.
|
|
58
|
+
#
|
|
59
|
+
# @return [Hash] the provider-formatted response
|
|
60
|
+
attribute :raw_response, writable: false
|
|
61
|
+
|
|
62
|
+
# Initializes a new response object with deep-duplicated attributes.
|
|
63
|
+
#
|
|
64
|
+
# Deep duplication ensures that the response object maintains its own
|
|
65
|
+
# independent copy of the data, preventing external modifications from
|
|
66
|
+
# affecting the response's internal state.
|
|
67
|
+
#
|
|
68
|
+
# @param kwargs [Hash] response attributes
|
|
69
|
+
# @option kwargs [Hash] :context the original request context
|
|
70
|
+
# @option kwargs [Hash] :raw_request the provider-formatted request
|
|
71
|
+
# @option kwargs [Hash] :raw_response the provider-formatted response
|
|
72
|
+
#
|
|
73
|
+
# @return [Base] the initialized response object
|
|
74
|
+
def initialize(kwargs = {})
|
|
75
|
+
super(kwargs.deep_dup) # Ensure that userland can't fuck with our memory space
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Extracts instructions from the context.
|
|
79
|
+
#
|
|
80
|
+
# @return [String, Array<Hash>, nil] the instructions that were sent to the provider
|
|
81
|
+
def instructions
|
|
82
|
+
context[:instructions]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Indicates whether the generation request was successful.
|
|
86
|
+
#
|
|
87
|
+
# @todo Better handling of failure flows
|
|
88
|
+
#
|
|
89
|
+
# @return [Boolean] true if successful, false otherwise
|
|
90
|
+
def success?
|
|
91
|
+
true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Extracts usage statistics from the raw response.
|
|
95
|
+
#
|
|
96
|
+
# Most providers (OpenAI, Anthropic, etc.) return usage data in a
|
|
97
|
+
# standardized format within the response. This method extracts that
|
|
98
|
+
# information for token counting and billing purposes.
|
|
99
|
+
#
|
|
100
|
+
# @return [Hash, nil] usage statistics hash with keys like "prompt_tokens",
|
|
101
|
+
# "completion_tokens", and "total_tokens", or nil if not available
|
|
102
|
+
#
|
|
103
|
+
# @example Usage data structure
|
|
104
|
+
# {
|
|
105
|
+
# "prompt_tokens" => 10,
|
|
106
|
+
# "completion_tokens" => 20,
|
|
107
|
+
# "total_tokens" => 30
|
|
108
|
+
# }
|
|
109
|
+
def usage
|
|
110
|
+
return nil unless raw_response
|
|
111
|
+
|
|
112
|
+
# Most providers store usage in the same format
|
|
113
|
+
if raw_response.is_a?(Hash) && raw_response["usage"]
|
|
114
|
+
raw_response["usage"]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Extracts the number of tokens used in the prompt/input.
|
|
119
|
+
#
|
|
120
|
+
# @return [Integer, nil] number of prompt tokens used, or nil if unavailable
|
|
121
|
+
#
|
|
122
|
+
# @example
|
|
123
|
+
# response.prompt_tokens #=> 10
|
|
124
|
+
def prompt_tokens
|
|
125
|
+
usage&.dig("prompt_tokens")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Extracts the number of tokens used in the completion/output.
|
|
129
|
+
#
|
|
130
|
+
# @return [Integer, nil] number of completion tokens used, or nil if unavailable
|
|
131
|
+
#
|
|
132
|
+
# @example
|
|
133
|
+
# response.completion_tokens #=> 20
|
|
134
|
+
def completion_tokens
|
|
135
|
+
usage&.dig("completion_tokens")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Extracts the total number of tokens used (prompt + completion).
|
|
139
|
+
#
|
|
140
|
+
# @return [Integer, nil] total number of tokens used, or nil if unavailable
|
|
141
|
+
#
|
|
142
|
+
# @example
|
|
143
|
+
# response.total_tokens #=> 30
|
|
144
|
+
def total_tokens
|
|
145
|
+
usage&.dig("total_tokens")
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Common
|
|
8
|
+
module Responses
|
|
9
|
+
# Response model for embedding responses
|
|
10
|
+
#
|
|
11
|
+
# This class represents responses from embedding endpoints.
|
|
12
|
+
# It includes the embedding data, the original context, raw API data,
|
|
13
|
+
# and usage statistics.
|
|
14
|
+
#
|
|
15
|
+
# == Example
|
|
16
|
+
#
|
|
17
|
+
# response = EmbedResponse.new(
|
|
18
|
+
# context: context_hash,
|
|
19
|
+
# data: [embedding_array],
|
|
20
|
+
# raw_response: { "usage" => { "prompt_tokens" => 10 } }
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# response.data #=> [[0.1, 0.2, ...]]
|
|
24
|
+
# response.prompt_tokens #=> 10
|
|
25
|
+
# response.usage #=> { "prompt_tokens" => 10, ... }
|
|
26
|
+
class Embed < Base
|
|
27
|
+
# The embedding data
|
|
28
|
+
attribute :data, writable: false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|