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,264 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "content/_types"
|
|
4
|
+
|
|
5
|
+
require_relative "base"
|
|
6
|
+
require_relative "tool_call_base"
|
|
7
|
+
require_relative "input_message"
|
|
8
|
+
require_relative "output_message"
|
|
9
|
+
require_relative "user_message"
|
|
10
|
+
require_relative "system_message"
|
|
11
|
+
require_relative "developer_message"
|
|
12
|
+
require_relative "assistant_message"
|
|
13
|
+
require_relative "tool_message"
|
|
14
|
+
require_relative "function_call_output"
|
|
15
|
+
require_relative "item_reference"
|
|
16
|
+
require_relative "reasoning"
|
|
17
|
+
|
|
18
|
+
# Tool call types
|
|
19
|
+
require_relative "file_search_tool_call"
|
|
20
|
+
require_relative "computer_tool_call"
|
|
21
|
+
require_relative "computer_tool_call_output"
|
|
22
|
+
require_relative "web_search_tool_call"
|
|
23
|
+
require_relative "function_tool_call"
|
|
24
|
+
require_relative "image_gen_tool_call"
|
|
25
|
+
require_relative "code_interpreter_tool_call"
|
|
26
|
+
require_relative "local_shell_tool_call"
|
|
27
|
+
require_relative "local_shell_tool_call_output"
|
|
28
|
+
require_relative "custom_tool_call"
|
|
29
|
+
require_relative "custom_tool_call_output"
|
|
30
|
+
|
|
31
|
+
# MCP types
|
|
32
|
+
require_relative "mcp_list_tools"
|
|
33
|
+
require_relative "mcp_approval_request"
|
|
34
|
+
require_relative "mcp_approval_response"
|
|
35
|
+
require_relative "mcp_tool_call"
|
|
36
|
+
|
|
37
|
+
module ActiveAgent
|
|
38
|
+
module Providers
|
|
39
|
+
module OpenAI
|
|
40
|
+
module Responses
|
|
41
|
+
module Requests
|
|
42
|
+
module Inputs
|
|
43
|
+
# Type for handling items (array of items - full Item types)
|
|
44
|
+
class ItemsType < ActiveModel::Type::Value
|
|
45
|
+
def initialize
|
|
46
|
+
super
|
|
47
|
+
@item_type = ItemType.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def cast(value)
|
|
51
|
+
case value
|
|
52
|
+
when String
|
|
53
|
+
# Plain text string becomes array with single user message
|
|
54
|
+
[ UserMessage.new(text: value) ]
|
|
55
|
+
when Array
|
|
56
|
+
value.map { |item| @item_type.cast(item) }
|
|
57
|
+
when Hash
|
|
58
|
+
# Single hash becomes array with one item
|
|
59
|
+
[ @item_type.cast(value) ]
|
|
60
|
+
when nil
|
|
61
|
+
nil
|
|
62
|
+
else
|
|
63
|
+
raise ArgumentError, "Cannot cast #{value.class} to Items (expected String, Array, Hash, or nil)"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def serialize(value)
|
|
68
|
+
case value
|
|
69
|
+
when String
|
|
70
|
+
value
|
|
71
|
+
when Array
|
|
72
|
+
value.map { |v| @item_type.serialize(v) }
|
|
73
|
+
when Hash
|
|
74
|
+
@item_type.serialize(value)
|
|
75
|
+
when nil
|
|
76
|
+
nil
|
|
77
|
+
else
|
|
78
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def deserialize(value)
|
|
83
|
+
cast(value)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Type for handling individual items (messages, tool calls, reasoning, etc.)
|
|
88
|
+
class ItemType < ActiveModel::Type::Value
|
|
89
|
+
def initialize
|
|
90
|
+
super
|
|
91
|
+
@content_type = Content::ContentType.new
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def cast(value)
|
|
95
|
+
case value
|
|
96
|
+
when ::OpenAI::Internal::Type::BaseModel
|
|
97
|
+
cast(value.to_h)
|
|
98
|
+
when Base
|
|
99
|
+
value
|
|
100
|
+
when String
|
|
101
|
+
# Plain text string becomes user message
|
|
102
|
+
UserMessage.new(text: value)
|
|
103
|
+
when Hash
|
|
104
|
+
hash = value.deep_symbolize_keys
|
|
105
|
+
type = hash[:type]&.to_sym
|
|
106
|
+
|
|
107
|
+
case type
|
|
108
|
+
# Message types
|
|
109
|
+
when :message, nil
|
|
110
|
+
cast_message(hash)
|
|
111
|
+
# Tool call types
|
|
112
|
+
when :file_search_call
|
|
113
|
+
FileSearchToolCall.new(**hash)
|
|
114
|
+
when :computer_call
|
|
115
|
+
ComputerToolCall.new(**hash)
|
|
116
|
+
when :computer_call_output
|
|
117
|
+
ComputerToolCallOutput.new(**hash)
|
|
118
|
+
when :web_search_call
|
|
119
|
+
WebSearchToolCall.new(**hash)
|
|
120
|
+
when :function_call
|
|
121
|
+
FunctionToolCall.new(**hash)
|
|
122
|
+
when :function_call_output
|
|
123
|
+
FunctionCallOutput.new(**hash)
|
|
124
|
+
when :image_generation_call
|
|
125
|
+
ImageGenToolCall.new(**hash)
|
|
126
|
+
when :code_interpreter_call
|
|
127
|
+
CodeInterpreterToolCall.new(**hash)
|
|
128
|
+
when :local_shell_call
|
|
129
|
+
LocalShellToolCall.new(**hash)
|
|
130
|
+
when :local_shell_call_output
|
|
131
|
+
LocalShellToolCallOutput.new(**hash)
|
|
132
|
+
when :custom_tool_call
|
|
133
|
+
CustomToolCall.new(**hash)
|
|
134
|
+
when :custom_tool_call_output
|
|
135
|
+
CustomToolCallOutput.new(**hash)
|
|
136
|
+
# MCP types
|
|
137
|
+
when :mcp_list_tools
|
|
138
|
+
MCPListTools.new(**hash)
|
|
139
|
+
when :mcp_approval_request
|
|
140
|
+
MCPApprovalRequest.new(**hash)
|
|
141
|
+
when :mcp_approval_response
|
|
142
|
+
MCPApprovalResponse.new(**hash)
|
|
143
|
+
when :mcp_call
|
|
144
|
+
MCPToolCall.new(**hash)
|
|
145
|
+
# Other types
|
|
146
|
+
when :reasoning
|
|
147
|
+
Reasoning.new(**hash)
|
|
148
|
+
when :item_reference
|
|
149
|
+
ItemReference.new(**hash)
|
|
150
|
+
else
|
|
151
|
+
raise ArgumentError, "Unknown item type: #{type.inspect}"
|
|
152
|
+
end
|
|
153
|
+
when nil
|
|
154
|
+
nil
|
|
155
|
+
else
|
|
156
|
+
raise ArgumentError, "Cannot cast #{value.class} to Item (expected Base, Hash, String, or nil)"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def serialize(value)
|
|
161
|
+
case value
|
|
162
|
+
when Base
|
|
163
|
+
hash = value.serialize
|
|
164
|
+
|
|
165
|
+
if hash[:content] in [ { type: "input_text", text: String } ]
|
|
166
|
+
hash[:content] = hash[:content].first[:text]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
hash
|
|
170
|
+
when Hash
|
|
171
|
+
value
|
|
172
|
+
when nil
|
|
173
|
+
nil
|
|
174
|
+
else
|
|
175
|
+
raise ArgumentError, "Cannot serialize #{value.class} as Item"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def deserialize(value)
|
|
180
|
+
cast(value)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
def cast_message(hash)
|
|
186
|
+
role = hash[:role]&.to_sym
|
|
187
|
+
|
|
188
|
+
case role
|
|
189
|
+
when :system
|
|
190
|
+
SystemMessage.new(**hash)
|
|
191
|
+
when :developer
|
|
192
|
+
DeveloperMessage.new(**hash)
|
|
193
|
+
when :user, nil
|
|
194
|
+
UserMessage.new(**hash)
|
|
195
|
+
when :assistant
|
|
196
|
+
AssistantMessage.new(**hash)
|
|
197
|
+
when :tool
|
|
198
|
+
ToolMessage.new(**hash)
|
|
199
|
+
else
|
|
200
|
+
raise ArgumentError, "Unknown message role: #{role.inspect}"
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Type for handling messages (array of messages) - kept for backwards compatibility
|
|
206
|
+
class MessagesType < ActiveModel::Type::Value
|
|
207
|
+
def initialize
|
|
208
|
+
super
|
|
209
|
+
@item_type = ItemType.new
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def cast(value)
|
|
213
|
+
case value
|
|
214
|
+
when String
|
|
215
|
+
value
|
|
216
|
+
when Array
|
|
217
|
+
value.map { |item| @item_type.cast(item) }
|
|
218
|
+
when Hash
|
|
219
|
+
# Single hash becomes array with one message
|
|
220
|
+
[ @item_type.cast(value) ]
|
|
221
|
+
when nil
|
|
222
|
+
nil
|
|
223
|
+
else
|
|
224
|
+
raise ArgumentError, "Cannot cast #{value.class} to Input (expected String, Array, or Hash)"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def serialize(value)
|
|
229
|
+
case value
|
|
230
|
+
when String
|
|
231
|
+
value
|
|
232
|
+
when Array
|
|
233
|
+
grouped = []
|
|
234
|
+
|
|
235
|
+
value.each do |message|
|
|
236
|
+
if grouped.empty?
|
|
237
|
+
grouped << message.deep_dup
|
|
238
|
+
elsif grouped.last.role == message.role && grouped.last.type == message.type
|
|
239
|
+
grouped.last.content += message.content.deep_dup
|
|
240
|
+
else
|
|
241
|
+
grouped << message.deep_dup
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
grouped.map { |v| @item_type.serialize(v) }
|
|
246
|
+
when Hash
|
|
247
|
+
@item_type.serialize(value)
|
|
248
|
+
when nil
|
|
249
|
+
nil
|
|
250
|
+
else
|
|
251
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def deserialize(value)
|
|
256
|
+
cast(value)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "output_message"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Responses
|
|
9
|
+
module Requests
|
|
10
|
+
module Inputs
|
|
11
|
+
# Assistant message output for OpenAI Responses API.
|
|
12
|
+
#
|
|
13
|
+
# Represents an assistant message in the conversation history.
|
|
14
|
+
class AssistantMessage < OutputMessage
|
|
15
|
+
attribute :role, :string, as: "assistant"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
require_relative "content/_types"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module OpenAI
|
|
9
|
+
module Responses
|
|
10
|
+
module Requests
|
|
11
|
+
module Inputs
|
|
12
|
+
# Base class for input items in Responses API
|
|
13
|
+
class Base < Common::BaseModel
|
|
14
|
+
attribute :role, :string
|
|
15
|
+
attribute :content, Content::ContentsType.new
|
|
16
|
+
|
|
17
|
+
validates :role, inclusion: {
|
|
18
|
+
in: %w[system user assistant developer tool],
|
|
19
|
+
allow_nil: true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Define content setter methods for different content types
|
|
23
|
+
%i[text image document].each do |content_type|
|
|
24
|
+
define_method(:"#{content_type}=") do |value|
|
|
25
|
+
self.content ||= []
|
|
26
|
+
self.content += [ { content_type => value } ]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Converts to common format.
|
|
31
|
+
#
|
|
32
|
+
# @return [Hash] message in canonical format
|
|
33
|
+
def to_common
|
|
34
|
+
{
|
|
35
|
+
role: map_role_to_common,
|
|
36
|
+
content: extract_text_content,
|
|
37
|
+
name: respond_to?(:name) ? name : nil,
|
|
38
|
+
tool_call_id: respond_to?(:tool_call_id) ? tool_call_id : nil
|
|
39
|
+
}.compact
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Maps OpenAI roles to canonical roles.
|
|
45
|
+
#
|
|
46
|
+
# @return [String] canonical role name
|
|
47
|
+
def map_role_to_common
|
|
48
|
+
case role
|
|
49
|
+
when "developer", "system"
|
|
50
|
+
"system"
|
|
51
|
+
when "user"
|
|
52
|
+
"user"
|
|
53
|
+
when "assistant"
|
|
54
|
+
"assistant"
|
|
55
|
+
when "tool", "function"
|
|
56
|
+
"tool"
|
|
57
|
+
else
|
|
58
|
+
role
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Extracts text content from OpenAI's content structure.
|
|
63
|
+
#
|
|
64
|
+
# @return [String, nil] extracted text content
|
|
65
|
+
def extract_text_content
|
|
66
|
+
return nil unless respond_to?(:content)
|
|
67
|
+
|
|
68
|
+
case content
|
|
69
|
+
when String
|
|
70
|
+
content
|
|
71
|
+
when Array
|
|
72
|
+
# For Responses API, content is an array of content objects (InputText, etc.)
|
|
73
|
+
content.select { |part| part.respond_to?(:text) }
|
|
74
|
+
.map(&:text)
|
|
75
|
+
.compact
|
|
76
|
+
.join("\n")
|
|
77
|
+
when nil
|
|
78
|
+
nil
|
|
79
|
+
else
|
|
80
|
+
content.to_s
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tool_call_base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Responses
|
|
9
|
+
module Requests
|
|
10
|
+
module Inputs
|
|
11
|
+
# Code interpreter tool call - runs Python code
|
|
12
|
+
class CodeInterpreterToolCall < ToolCallBase
|
|
13
|
+
attribute :type, :string, as: "code_interpreter_call"
|
|
14
|
+
attribute :container_id, :string
|
|
15
|
+
attribute :code, :string # Can be null
|
|
16
|
+
attribute :outputs # Always an array of output objects, can be empty
|
|
17
|
+
|
|
18
|
+
validates :type, inclusion: { in: %w[code_interpreter_call], allow_nil: false }
|
|
19
|
+
validates :container_id, presence: true
|
|
20
|
+
validates :status, inclusion: {
|
|
21
|
+
in: %w[in_progress completed incomplete interpreting failed],
|
|
22
|
+
allow_nil: false
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tool_call_base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Responses
|
|
9
|
+
module Requests
|
|
10
|
+
module Inputs
|
|
11
|
+
# Computer tool call - computer use tool
|
|
12
|
+
class ComputerToolCall < ToolCallBase
|
|
13
|
+
attribute :type, :string, as: "computer_call"
|
|
14
|
+
attribute :call_id, :string
|
|
15
|
+
attribute :action # ComputerAction object
|
|
16
|
+
attribute :pending_safety_checks # Always an array of safety check objects
|
|
17
|
+
|
|
18
|
+
validates :type, inclusion: { in: %w[computer_call], allow_nil: false }
|
|
19
|
+
validates :call_id, presence: true
|
|
20
|
+
validates :action, presence: true
|
|
21
|
+
validates :pending_safety_checks, presence: true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Responses
|
|
9
|
+
module Requests
|
|
10
|
+
module Inputs
|
|
11
|
+
# Computer tool call output
|
|
12
|
+
class ComputerToolCallOutput < Base
|
|
13
|
+
attribute :type, :string, as: "computer_call_output"
|
|
14
|
+
attribute :id, :string
|
|
15
|
+
attribute :call_id, :string
|
|
16
|
+
attribute :acknowledged_safety_checks # Always an array of safety check objects
|
|
17
|
+
attribute :output # ComputerScreenshotImage object
|
|
18
|
+
attribute :status, :string
|
|
19
|
+
|
|
20
|
+
validates :type, inclusion: { in: %w[computer_call_output], allow_nil: false }
|
|
21
|
+
validates :call_id, presence: true
|
|
22
|
+
validates :output, presence: true
|
|
23
|
+
validates :status, inclusion: {
|
|
24
|
+
in: %w[in_progress completed incomplete],
|
|
25
|
+
allow_nil: true
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "input_audio"
|
|
5
|
+
require_relative "input_file"
|
|
6
|
+
require_relative "input_image"
|
|
7
|
+
require_relative "input_text"
|
|
8
|
+
|
|
9
|
+
module ActiveAgent
|
|
10
|
+
module Providers
|
|
11
|
+
module OpenAI
|
|
12
|
+
module Responses
|
|
13
|
+
module Requests
|
|
14
|
+
module Inputs
|
|
15
|
+
module Content
|
|
16
|
+
# Type for handling content (string or array of content parts)
|
|
17
|
+
class ContentsType < ActiveModel::Type::Value
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
@content_type = ContentType.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cast(value)
|
|
24
|
+
case value
|
|
25
|
+
when String
|
|
26
|
+
# Plain text string - keep as string
|
|
27
|
+
value
|
|
28
|
+
when Array
|
|
29
|
+
# Array of content parts - cast each part
|
|
30
|
+
value.map { |part| @content_type.cast(part) }
|
|
31
|
+
when nil
|
|
32
|
+
nil
|
|
33
|
+
else
|
|
34
|
+
raise ArgumentError, "Cannot cast #{value.class} to Contents (expected String, Array, or nil)"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def serialize(value)
|
|
39
|
+
case value
|
|
40
|
+
when String
|
|
41
|
+
value
|
|
42
|
+
when Array
|
|
43
|
+
value.map { |part| @content_type.serialize(part) }
|
|
44
|
+
when nil
|
|
45
|
+
nil
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError, "Cannot serialize #{value.class} as Contents"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def deserialize(value)
|
|
52
|
+
cast(value)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Type for individual content items
|
|
57
|
+
class ContentType < ActiveModel::Type::Value
|
|
58
|
+
def cast(value)
|
|
59
|
+
case value
|
|
60
|
+
when Base
|
|
61
|
+
value
|
|
62
|
+
when Hash
|
|
63
|
+
hash = value.deep_symbolize_keys
|
|
64
|
+
type = hash[:type]&.to_sym
|
|
65
|
+
|
|
66
|
+
case type
|
|
67
|
+
when :input_text, :output_text
|
|
68
|
+
InputText.new(**hash.except(:annotations, :logprobs, :type))
|
|
69
|
+
when :input_image
|
|
70
|
+
InputImage.new(**hash)
|
|
71
|
+
when :input_file
|
|
72
|
+
InputFile.new(**hash)
|
|
73
|
+
when nil
|
|
74
|
+
# When type is nil, check for specific content keys to infer type
|
|
75
|
+
if hash.key?(:text)
|
|
76
|
+
InputText.new(**hash)
|
|
77
|
+
elsif hash.key?(:image)
|
|
78
|
+
InputImage.new(**hash.merge(image_url: hash.delete(:image)))
|
|
79
|
+
elsif hash.key?(:document)
|
|
80
|
+
cast_document_to_file(hash)
|
|
81
|
+
else
|
|
82
|
+
raise ArgumentError, "Cannot determine content type from hash keys: #{hash.keys.inspect}"
|
|
83
|
+
end
|
|
84
|
+
else
|
|
85
|
+
raise ArgumentError, "Unknown content type: #{type.inspect}"
|
|
86
|
+
end
|
|
87
|
+
when String
|
|
88
|
+
# Plain text string becomes input_text
|
|
89
|
+
InputText.new(text: value)
|
|
90
|
+
when nil
|
|
91
|
+
nil
|
|
92
|
+
else
|
|
93
|
+
raise ArgumentError, "Cannot cast #{value.class} to Content (expected Base, Hash, String, or nil)"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def serialize(value)
|
|
98
|
+
case value
|
|
99
|
+
when Base
|
|
100
|
+
value.serialize
|
|
101
|
+
when Hash
|
|
102
|
+
value
|
|
103
|
+
when String
|
|
104
|
+
{ type: "input_text", text: value }
|
|
105
|
+
when nil
|
|
106
|
+
nil
|
|
107
|
+
else
|
|
108
|
+
raise ArgumentError, "Cannot serialize #{value.class} as Content"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def deserialize(value)
|
|
113
|
+
cast(value)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
def cast_document_to_file(hash)
|
|
119
|
+
document_value = hash.delete(:document)
|
|
120
|
+
|
|
121
|
+
case document_value
|
|
122
|
+
when String
|
|
123
|
+
if uri?(document_value)
|
|
124
|
+
# It's a URI/URL (http/https)
|
|
125
|
+
InputFile.new(**hash.merge(file_url: document_value))
|
|
126
|
+
elsif data_uri?(document_value)
|
|
127
|
+
# It's a data URI (e.g., data:application/pdf;base64,...)
|
|
128
|
+
# NOTE: While the OpenAI docs say filename is optional, it is required with base64 format
|
|
129
|
+
media_type, _data = parse_data_uri(document_value)
|
|
130
|
+
filename = generate_filename_from_media_type(media_type)
|
|
131
|
+
InputFile.new(**hash.merge(file_data: document_value, filename: filename))
|
|
132
|
+
else
|
|
133
|
+
raise ArgumentError, "Cannot determine source type for document value: #{document_value.inspect}"
|
|
134
|
+
end
|
|
135
|
+
else
|
|
136
|
+
raise ArgumentError, "Expected String for document key, got #{document_value.class}"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def uri?(value)
|
|
141
|
+
# Check if it looks like a URI (http://, https://, etc.)
|
|
142
|
+
value.match?(%r{\A(https?)://}i)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def data_uri?(value)
|
|
146
|
+
# Check if it's a data URI (data:...)
|
|
147
|
+
value.match?(/\Adata:/i)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def parse_data_uri(data_uri)
|
|
151
|
+
# Parse data URI format: data:mime/type;base64,encoded_data
|
|
152
|
+
match = data_uri.match(/\Adata:([^;,]+)(;base64)?,(.+)\z/i)
|
|
153
|
+
raise ArgumentError, "Invalid data URI format: #{data_uri[0..50]}..." unless match
|
|
154
|
+
|
|
155
|
+
media_type = match[1]
|
|
156
|
+
is_base64 = !match[2].nil?
|
|
157
|
+
data = match[3]
|
|
158
|
+
|
|
159
|
+
unless is_base64
|
|
160
|
+
raise ArgumentError, "Only base64-encoded data URIs are supported: #{data_uri[0..50]}..."
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
[ media_type, data ]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def generate_filename_from_media_type(media_type)
|
|
167
|
+
# Map common media types to file extensions
|
|
168
|
+
extension = case media_type
|
|
169
|
+
when "application/pdf"
|
|
170
|
+
"pdf"
|
|
171
|
+
when "application/msword"
|
|
172
|
+
"doc"
|
|
173
|
+
when "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
174
|
+
"docx"
|
|
175
|
+
when "application/vnd.ms-excel"
|
|
176
|
+
"xls"
|
|
177
|
+
when "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
178
|
+
"xlsx"
|
|
179
|
+
when "application/vnd.ms-powerpoint"
|
|
180
|
+
"ppt"
|
|
181
|
+
when "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
182
|
+
"pptx"
|
|
183
|
+
when "text/plain"
|
|
184
|
+
"txt"
|
|
185
|
+
when "text/csv"
|
|
186
|
+
"csv"
|
|
187
|
+
when "text/html"
|
|
188
|
+
"html"
|
|
189
|
+
when "application/json"
|
|
190
|
+
"json"
|
|
191
|
+
when "application/xml", "text/xml"
|
|
192
|
+
"xml"
|
|
193
|
+
else
|
|
194
|
+
# Try to extract extension from media type (e.g., "application/xyz" -> "xyz")
|
|
195
|
+
media_type.split("/").last.split("+").first
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
"document.#{extension}"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Responses
|
|
9
|
+
module Requests
|
|
10
|
+
module Inputs
|
|
11
|
+
module Content
|
|
12
|
+
# Base class for content parts
|
|
13
|
+
class Base < Common::BaseModel
|
|
14
|
+
attribute :type, :string
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|