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,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Chat
|
|
9
|
+
module Requests
|
|
10
|
+
module Messages
|
|
11
|
+
# Function message - result from a function call (deprecated)
|
|
12
|
+
class Function < Base
|
|
13
|
+
attribute :role, :string, as: "function"
|
|
14
|
+
attribute :content, :string # Result of the function call
|
|
15
|
+
attribute :name, :string # Name of the function that was called
|
|
16
|
+
|
|
17
|
+
validates :content, presence: true
|
|
18
|
+
validates :name, presence: true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "content/_types"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module OpenAI
|
|
9
|
+
module Chat
|
|
10
|
+
module Requests
|
|
11
|
+
module Messages
|
|
12
|
+
# System message - instructions that the model should follow (older models)
|
|
13
|
+
class System < Base
|
|
14
|
+
attribute :role, :string, as: "system"
|
|
15
|
+
attribute :content, Content::ContentsType.new # String or array of content parts
|
|
16
|
+
attribute :name, :string # Optional name for the participant
|
|
17
|
+
|
|
18
|
+
validates :content, presence: true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "content/_types"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module OpenAI
|
|
9
|
+
module Chat
|
|
10
|
+
module Requests
|
|
11
|
+
module Messages
|
|
12
|
+
# Tool message - result from a tool call
|
|
13
|
+
class Tool < Base
|
|
14
|
+
attribute :role, :string, as: "tool"
|
|
15
|
+
attribute :content, Content::ContentsType.new # String or array of content parts
|
|
16
|
+
attribute :tool_call_id, :string # ID of the tool call this is a response to
|
|
17
|
+
|
|
18
|
+
validates :content, presence: true
|
|
19
|
+
validates :tool_call_id, presence: true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require_relative "content/_types"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module OpenAI
|
|
9
|
+
module Chat
|
|
10
|
+
module Requests
|
|
11
|
+
module Messages
|
|
12
|
+
# User message - messages sent by an end user
|
|
13
|
+
class User < Base
|
|
14
|
+
attribute :role, :string, as: "user"
|
|
15
|
+
attribute :content, Content::ContentsType.new # String or array of content parts
|
|
16
|
+
attribute :name, :string # Optional name for the participant
|
|
17
|
+
|
|
18
|
+
validates :content, presence: true
|
|
19
|
+
|
|
20
|
+
%i[text image document].each do |content_type|
|
|
21
|
+
define_method(:"#{content_type}=") do |value|
|
|
22
|
+
self.content ||= []
|
|
23
|
+
self.content += [ { content_type => value } ]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
class Prediction < Common::BaseModel
|
|
11
|
+
# Type of predicted content (always "content")
|
|
12
|
+
attribute :type, :string, default: "content"
|
|
13
|
+
|
|
14
|
+
# Content that should be matched (string or array of content parts)
|
|
15
|
+
attribute :content
|
|
16
|
+
|
|
17
|
+
validates :type, inclusion: { in: %w[content] }, allow_nil: true
|
|
18
|
+
|
|
19
|
+
# Validate content is present and in correct format
|
|
20
|
+
validate :validate_content_format
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def validate_content_format
|
|
25
|
+
if content.blank?
|
|
26
|
+
errors.add(:content, "must be present")
|
|
27
|
+
return
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Content can be a string or an array of content parts
|
|
31
|
+
if content.is_a?(Array)
|
|
32
|
+
content.each do |part|
|
|
33
|
+
unless part.is_a?(Hash) && part[:type].present?
|
|
34
|
+
errors.add(:content, "array elements must be hashes with a 'type' field")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
elsif !content.is_a?(String)
|
|
38
|
+
errors.add(:content, "must be a string or array of content parts")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
class ResponseFormat < Common::BaseModel
|
|
11
|
+
# Type of response format (text, json_schema, json_object)
|
|
12
|
+
attribute :type, :string
|
|
13
|
+
|
|
14
|
+
# JSON schema configuration (only for json_schema type)
|
|
15
|
+
attribute :json_schema # Hash with name, description, schema, strict
|
|
16
|
+
|
|
17
|
+
validates :type, inclusion: { in: %w[text json_schema json_object] }, allow_nil: true
|
|
18
|
+
|
|
19
|
+
# Validate that json_schema is present when type is json_schema
|
|
20
|
+
validate :validate_json_schema_presence
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def validate_json_schema_presence
|
|
25
|
+
if type == "json_schema" && json_schema.blank?
|
|
26
|
+
errors.add(:json_schema, "must be present when type is 'json_schema'")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if json_schema.present? && json_schema.is_a?(Hash)
|
|
30
|
+
validate_json_schema_structure
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def validate_json_schema_structure
|
|
35
|
+
unless json_schema[:name].present?
|
|
36
|
+
errors.add(:json_schema, "must include 'name' field")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if json_schema[:name].present? && json_schema[:name].length > 64
|
|
40
|
+
errors.add(:json_schema, "name must be 64 characters or less")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Name must match pattern: a-z, A-Z, 0-9, underscores and dashes
|
|
44
|
+
if json_schema[:name].present? && json_schema[:name] !~ /^[a-zA-Z0-9_-]+$/
|
|
45
|
+
errors.add(:json_schema, "name must contain only a-z, A-Z, 0-9, underscores and dashes")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
class StreamOptions < Common::BaseModel
|
|
11
|
+
# Include usage information in the stream
|
|
12
|
+
attribute :include_usage, :boolean
|
|
13
|
+
|
|
14
|
+
# Include obfuscation in the stream
|
|
15
|
+
attribute :include_obfuscation, :boolean
|
|
16
|
+
|
|
17
|
+
validates :include_usage, inclusion: { in: [ true, false ] }, allow_nil: true
|
|
18
|
+
validates :include_obfuscation, inclusion: { in: [ true, false ] }, allow_nil: true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
# Tool choice configuration
|
|
11
|
+
class ToolChoice < Common::BaseModel
|
|
12
|
+
# Can be string ("none", "auto", "required") or object
|
|
13
|
+
attribute :mode, :string
|
|
14
|
+
attribute :type, :string
|
|
15
|
+
attribute :function # Hash with name
|
|
16
|
+
attribute :custom # Hash with name
|
|
17
|
+
attribute :allowed_tools # Hash with mode and tools array
|
|
18
|
+
|
|
19
|
+
validates :mode, inclusion: { in: %w[none auto required] }, allow_nil: true
|
|
20
|
+
validates :type, inclusion: { in: %w[function custom allowed_tools] }, allow_nil: true
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
module Tools
|
|
11
|
+
# Base class for tools
|
|
12
|
+
class Base < Common::BaseModel
|
|
13
|
+
attribute :type, :string
|
|
14
|
+
|
|
15
|
+
validates :type, inclusion: { in: %w[function custom] }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Chat
|
|
9
|
+
module Requests
|
|
10
|
+
module Tools
|
|
11
|
+
# Custom tool
|
|
12
|
+
class CustomTool < Base
|
|
13
|
+
attribute :type, :string, as: "custom"
|
|
14
|
+
attribute :custom # Hash with name, description, format
|
|
15
|
+
|
|
16
|
+
validate :validate_custom_structure
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def validate_custom_structure
|
|
21
|
+
if custom.blank?
|
|
22
|
+
errors.add(:custom, "must be present")
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
unless custom.is_a?(Hash)
|
|
27
|
+
errors.add(:custom, "must be a hash")
|
|
28
|
+
return
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
unless custom[:name].present?
|
|
32
|
+
errors.add(:custom, "must include 'name' field")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module OpenAI
|
|
8
|
+
module Chat
|
|
9
|
+
module Requests
|
|
10
|
+
module Tools
|
|
11
|
+
# Function tool
|
|
12
|
+
class FunctionTool < Base
|
|
13
|
+
attribute :type, :string, as: "function"
|
|
14
|
+
attribute :function # Hash with name, description, parameters, strict
|
|
15
|
+
|
|
16
|
+
validate :validate_function_structure
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def validate_function_structure
|
|
21
|
+
if function.blank?
|
|
22
|
+
errors.add(:function, "must be present")
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
unless function.is_a?(Hash)
|
|
27
|
+
errors.add(:function, "must be a hash")
|
|
28
|
+
return
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
unless function[:name].present?
|
|
32
|
+
errors.add(:function, "must include 'name' field")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if function[:name].present?
|
|
36
|
+
if function[:name].length > 64
|
|
37
|
+
errors.add(:function, "name must be 64 characters or less")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
unless function[:name] =~ /^[a-zA-Z0-9_-]+$/
|
|
41
|
+
errors.add(:function, "name must contain only a-z, A-Z, 0-9, underscores and dashes")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
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 Chat
|
|
9
|
+
module Requests
|
|
10
|
+
class WebSearchOptions < Common::BaseModel
|
|
11
|
+
# Search context size (low, medium, high)
|
|
12
|
+
attribute :search_context_size, :string
|
|
13
|
+
|
|
14
|
+
# User location for search
|
|
15
|
+
attribute :user_location # Hash with type and approximate
|
|
16
|
+
|
|
17
|
+
validates :search_context_size, inclusion: { in: %w[low medium high] }, allow_nil: true
|
|
18
|
+
|
|
19
|
+
# Validate user_location format
|
|
20
|
+
validate :validate_user_location_format
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def validate_user_location_format
|
|
25
|
+
return if user_location.nil?
|
|
26
|
+
|
|
27
|
+
unless user_location.is_a?(Hash)
|
|
28
|
+
errors.add(:user_location, "must be a hash")
|
|
29
|
+
return
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
unless user_location[:type] == "approximate"
|
|
33
|
+
errors.add(:user_location, "type must be 'approximate'")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
unless user_location[:approximate].is_a?(Hash)
|
|
37
|
+
errors.add(:user_location, "must include 'approximate' hash")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
require_relative "_base"
|
|
2
|
+
require_relative "chat/_types"
|
|
3
|
+
|
|
4
|
+
module ActiveAgent
|
|
5
|
+
module Providers
|
|
6
|
+
module OpenAI
|
|
7
|
+
# Provider implementation for OpenAI's Chat Completion API.
|
|
8
|
+
#
|
|
9
|
+
# Handles chat-based interactions including streaming responses,
|
|
10
|
+
# function/tool calling, and message management. Uses OpenAI's
|
|
11
|
+
# chat completions endpoint for generating responses.
|
|
12
|
+
#
|
|
13
|
+
# @see Base
|
|
14
|
+
# @see https://platform.openai.com/docs/api-reference/chat
|
|
15
|
+
class ChatProvider < Base
|
|
16
|
+
# @return [Class] the options class for this provider
|
|
17
|
+
def self.options_klass
|
|
18
|
+
Options
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Chat::RequestType] request type instance for chat completions
|
|
22
|
+
def self.prompt_request_type
|
|
23
|
+
Chat::RequestType.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
# @return [OpenAI::Client::Completions] the API client for chat completions
|
|
29
|
+
# @see Base#api_prompt_executer
|
|
30
|
+
def api_prompt_executer
|
|
31
|
+
client.chat.completions
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Processes streaming response chunks from OpenAI's chat API.
|
|
35
|
+
#
|
|
36
|
+
# Handles message deltas, content updates, and completion detection.
|
|
37
|
+
# Manages the message stack and broadcasts streaming updates.
|
|
38
|
+
#
|
|
39
|
+
# Handles multiple event types:
|
|
40
|
+
# - `:chunk` - Message content and tool call deltas
|
|
41
|
+
# - `:"content.delta"` - Incremental content updates
|
|
42
|
+
# - `:"content.done"` - Complete content delivery
|
|
43
|
+
# - `:"tool_calls.function.arguments.delta"` - Tool argument deltas
|
|
44
|
+
# - `:"tool_calls.function.arguments.done"` - Complete tool arguments
|
|
45
|
+
#
|
|
46
|
+
# @param api_response_event [OpenAI::Helpers::Streaming::ChatChunkEvent]
|
|
47
|
+
# @return [void]
|
|
48
|
+
# @see Base#process_stream_chunk
|
|
49
|
+
def process_stream_chunk(api_response_event)
|
|
50
|
+
instrument("stream_chunk_processing.provider.active_agent")
|
|
51
|
+
|
|
52
|
+
# Called Multiple Times: [Chunk<T>, T]<Content, ToolsCall>
|
|
53
|
+
case api_response_event.type
|
|
54
|
+
when :chunk
|
|
55
|
+
api_message = api_response_event.chunk.choices.first
|
|
56
|
+
|
|
57
|
+
# If we have a delta, we need to update a message in the stack
|
|
58
|
+
message = find_or_create_message(api_message.index)
|
|
59
|
+
message = message_merge_delta(message, api_message.delta.as_json.deep_symbolize_keys)
|
|
60
|
+
|
|
61
|
+
# Stream back content changes as they come in
|
|
62
|
+
if api_message.delta.content
|
|
63
|
+
broadcast_stream_update(message_stack.last, api_message.delta.content)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# If this is the last api_chunk to be processed
|
|
67
|
+
return unless api_message.finish_reason
|
|
68
|
+
|
|
69
|
+
instrument("stream_finished.provider.active_agent", finish_reason: api_message.finish_reason)
|
|
70
|
+
when :"content.delta"
|
|
71
|
+
# Returns the deltas, without context
|
|
72
|
+
# => {type: :"content.delta", delta: "", snapshot: "", parsed: nil}
|
|
73
|
+
# => {type: :"content.delta", delta: "Hi", snapshot: "Hi", parsed: nil}
|
|
74
|
+
when :"content.done"
|
|
75
|
+
# Returns the full content when complete
|
|
76
|
+
# => {type: :"content.done", content: "Hi there! How can I help you today?", parsed: nil}
|
|
77
|
+
|
|
78
|
+
# Once we are finished, close out and run tooling callbacks (Recursive)
|
|
79
|
+
process_prompt_finished
|
|
80
|
+
when :"tool_calls.function.arguments.delta"
|
|
81
|
+
# => {type: :"tool_calls.function.arguments.delta", name: "get_current_weather", index: 0, arguments: "", parsed: nil, arguments_delta: ""}
|
|
82
|
+
when :"tool_calls.function.arguments.done"
|
|
83
|
+
# => => {type: :"tool_calls.function.arguments.done", index: 0, name: "get_current_weather", arguments: "{\"location\":\"Boston, MA\"}", parsed: nil}
|
|
84
|
+
else
|
|
85
|
+
fail "Unexpected Response Event Type: #{api_response_event.type}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Processes function/tool calls from the API response.
|
|
90
|
+
#
|
|
91
|
+
# Executes each tool call and creates tool response messages
|
|
92
|
+
# for the next iteration of the conversation.
|
|
93
|
+
#
|
|
94
|
+
# @param api_function_calls [Array<Hash>] function call objects with :type, :id, and :function keys
|
|
95
|
+
# @return [void]
|
|
96
|
+
# @see Base#process_function_calls
|
|
97
|
+
def process_function_calls(api_function_calls)
|
|
98
|
+
api_function_calls.each do |api_function_call|
|
|
99
|
+
content = case api_function_call[:type]
|
|
100
|
+
when "function"
|
|
101
|
+
instrument("tool_execution.provider.active_agent", tool_name: api_function_call.dig(:function, :name))
|
|
102
|
+
process_tool_call_function(api_function_call[:function])
|
|
103
|
+
else
|
|
104
|
+
fail "Unexpected Tool Call Type: #{api_function_call[:type]}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
message = Chat::Requests::Messages::Tool.new(
|
|
108
|
+
tool_call_id: api_function_call[:id],
|
|
109
|
+
content: content.to_json
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
message_stack.push(message.serialize)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Extracts messages from the completed API response.
|
|
117
|
+
#
|
|
118
|
+
# @param api_response [Hash]
|
|
119
|
+
# @return [Array<Hash>, nil] single-element array with message or nil if no message
|
|
120
|
+
# @see Base#process_prompt_finished_extract_messages
|
|
121
|
+
def process_prompt_finished_extract_messages(api_response)
|
|
122
|
+
api_message = api_response&.dig(:choices, 0, :message)
|
|
123
|
+
|
|
124
|
+
[ api_message ] if api_message
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Extracts function calls from the last message in the stack.
|
|
128
|
+
#
|
|
129
|
+
# @return [Array<Hash>, nil] tool call objects or nil if no tool calls
|
|
130
|
+
# @see Base#process_prompt_finished_extract_function_calls
|
|
131
|
+
def process_prompt_finished_extract_function_calls
|
|
132
|
+
message_stack.last[:tool_calls]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Merges streaming delta into a message.
|
|
136
|
+
#
|
|
137
|
+
# Separated from hash_merge_delta to allow Ollama to override role handling.
|
|
138
|
+
#
|
|
139
|
+
# @param message [Hash]
|
|
140
|
+
# @param delta [Hash]
|
|
141
|
+
# @return [Hash] the merged message
|
|
142
|
+
def message_merge_delta(message, delta)
|
|
143
|
+
hash_merge_delta(message, delta)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
# Finds an existing message by ID or creates a new one.
|
|
149
|
+
#
|
|
150
|
+
# @param id [Integer]
|
|
151
|
+
# @return [Hash] found or newly created message
|
|
152
|
+
def find_or_create_message(id)
|
|
153
|
+
message = message_stack.find { _1[:index] == id }
|
|
154
|
+
return message if message
|
|
155
|
+
|
|
156
|
+
message_stack << { index: id }
|
|
157
|
+
message_stack.last
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Recursively merges delta changes into a hash structure.
|
|
161
|
+
#
|
|
162
|
+
# Handles the complex delta merging needed for OpenAI's streaming API,
|
|
163
|
+
# including arrays with indexed items and string concatenation.
|
|
164
|
+
#
|
|
165
|
+
# @param hash [Hash] target hash to merge into
|
|
166
|
+
# @param delta [Hash] delta changes to apply
|
|
167
|
+
# @return [Hash] the merged hash
|
|
168
|
+
def hash_merge_delta(hash, delta)
|
|
169
|
+
delta.each do |key, value|
|
|
170
|
+
case hash[key]
|
|
171
|
+
when Hash
|
|
172
|
+
hash[key] = hash_merge_delta(hash[key], value)
|
|
173
|
+
when Array
|
|
174
|
+
value.each do |delta_item|
|
|
175
|
+
if delta_item.is_a?(Hash) && delta_item[:index]
|
|
176
|
+
hash_item = hash[key].find { _1[:index] == delta_item[:index] }
|
|
177
|
+
if hash_item
|
|
178
|
+
hash_merge_delta(hash_item, delta_item)
|
|
179
|
+
else
|
|
180
|
+
hash[key] << delta_item
|
|
181
|
+
end
|
|
182
|
+
else
|
|
183
|
+
hash[key] << delta_item
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
when String
|
|
187
|
+
hash[key] += value
|
|
188
|
+
else
|
|
189
|
+
hash[key] = value
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
hash
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "requests/_types"
|
|
4
|
+
require_relative "request"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
module OpenAI
|
|
9
|
+
module Embedding
|
|
10
|
+
# Type for Request model
|
|
11
|
+
class RequestType < ActiveModel::Type::Value
|
|
12
|
+
def cast(value)
|
|
13
|
+
case value
|
|
14
|
+
when Request
|
|
15
|
+
value
|
|
16
|
+
when Hash
|
|
17
|
+
Request.new(**value.deep_symbolize_keys)
|
|
18
|
+
when nil
|
|
19
|
+
nil
|
|
20
|
+
else
|
|
21
|
+
raise ArgumentError, "Cannot cast #{value.class} to Request"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def serialize(value)
|
|
26
|
+
case value
|
|
27
|
+
when Request
|
|
28
|
+
value.serialize
|
|
29
|
+
when Hash
|
|
30
|
+
value
|
|
31
|
+
when nil
|
|
32
|
+
nil
|
|
33
|
+
else
|
|
34
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def deserialize(value)
|
|
39
|
+
cast(value)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|