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,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "options"
|
|
4
|
+
require_relative "request"
|
|
5
|
+
require_relative "embedding_request"
|
|
6
|
+
|
|
7
|
+
module ActiveAgent
|
|
8
|
+
module Providers
|
|
9
|
+
module Mock
|
|
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
|
+
|
|
43
|
+
# Type for EmbeddingRequest model
|
|
44
|
+
class EmbeddingRequestType < ActiveModel::Type::Value
|
|
45
|
+
def cast(value)
|
|
46
|
+
case value
|
|
47
|
+
when EmbeddingRequest
|
|
48
|
+
value
|
|
49
|
+
when Hash
|
|
50
|
+
EmbeddingRequest.new(**value.deep_symbolize_keys)
|
|
51
|
+
when nil
|
|
52
|
+
nil
|
|
53
|
+
else
|
|
54
|
+
raise ArgumentError, "Cannot cast #{value.class} to EmbeddingRequest"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def serialize(value)
|
|
59
|
+
case value
|
|
60
|
+
when EmbeddingRequest
|
|
61
|
+
value.serialize
|
|
62
|
+
when Hash
|
|
63
|
+
value
|
|
64
|
+
when nil
|
|
65
|
+
nil
|
|
66
|
+
else
|
|
67
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def deserialize(value)
|
|
72
|
+
cast(value)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -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 Mock
|
|
8
|
+
# Embedding request model for Mock provider.
|
|
9
|
+
class EmbeddingRequest < Common::BaseModel
|
|
10
|
+
attribute :model, :string, default: "mock-embedding-model"
|
|
11
|
+
attribute :input # String or array of strings to embed
|
|
12
|
+
attribute :encoding_format, :string
|
|
13
|
+
attribute :dimensions, :integer
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Load all message classes
|
|
4
|
+
require_relative "base"
|
|
5
|
+
require_relative "user"
|
|
6
|
+
require_relative "assistant"
|
|
7
|
+
|
|
8
|
+
module ActiveAgent
|
|
9
|
+
module Providers
|
|
10
|
+
module Mock
|
|
11
|
+
module Messages
|
|
12
|
+
# Type for Messages array
|
|
13
|
+
class MessagesType < ActiveModel::Type::Value
|
|
14
|
+
def initialize
|
|
15
|
+
super
|
|
16
|
+
@message_type = MessageType.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def cast(value)
|
|
20
|
+
case value
|
|
21
|
+
when Array
|
|
22
|
+
value.map { |v| @message_type.cast(v) }
|
|
23
|
+
when nil
|
|
24
|
+
nil
|
|
25
|
+
else
|
|
26
|
+
raise ArgumentError, "Cannot cast #{value.class} to Messages array"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def serialize(value)
|
|
31
|
+
case value
|
|
32
|
+
when Array
|
|
33
|
+
grouped = []
|
|
34
|
+
|
|
35
|
+
value.each do |message|
|
|
36
|
+
if grouped.empty? || grouped.last.role != message.role
|
|
37
|
+
grouped << message.deep_dup
|
|
38
|
+
else
|
|
39
|
+
grouped.last.content += message.content.deep_dup
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
grouped.map { |v| @message_type.serialize(v) }
|
|
44
|
+
when nil
|
|
45
|
+
nil
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def deserialize(value)
|
|
52
|
+
cast(value)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Type for individual Message
|
|
57
|
+
class MessageType < ActiveModel::Type::Value
|
|
58
|
+
def cast(value)
|
|
59
|
+
case value
|
|
60
|
+
when Base
|
|
61
|
+
value
|
|
62
|
+
when String
|
|
63
|
+
User.new(content: value)
|
|
64
|
+
when Hash
|
|
65
|
+
hash = value.deep_symbolize_keys
|
|
66
|
+
role = hash[:role]&.to_sym
|
|
67
|
+
|
|
68
|
+
case role
|
|
69
|
+
when :user, nil
|
|
70
|
+
User.new(**hash)
|
|
71
|
+
when :assistant
|
|
72
|
+
Assistant.new(**hash)
|
|
73
|
+
else
|
|
74
|
+
raise ArgumentError, "Unknown message role: #{role}"
|
|
75
|
+
end
|
|
76
|
+
when nil
|
|
77
|
+
nil
|
|
78
|
+
else
|
|
79
|
+
raise ArgumentError, "Cannot cast #{value.class} to Message"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def serialize(value)
|
|
84
|
+
case value
|
|
85
|
+
when Base
|
|
86
|
+
value.serialize
|
|
87
|
+
when Hash
|
|
88
|
+
value
|
|
89
|
+
when nil
|
|
90
|
+
nil
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError, "Cannot serialize #{value.class}"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def deserialize(value)
|
|
97
|
+
cast(value)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Mock
|
|
8
|
+
module Messages
|
|
9
|
+
# Assistant message for Mock provider.
|
|
10
|
+
#
|
|
11
|
+
# Drops extra fields that are part of the API response but not
|
|
12
|
+
# part of the message structure (usage, id, model, stop_reason, type, etc).
|
|
13
|
+
class Assistant < Base
|
|
14
|
+
attribute :role, :string, as: "assistant"
|
|
15
|
+
attribute :content # Can be string or array of content blocks
|
|
16
|
+
attribute :name, :string
|
|
17
|
+
|
|
18
|
+
validates :content, presence: true
|
|
19
|
+
|
|
20
|
+
# Drop API response fields that aren't part of the message
|
|
21
|
+
drop_attributes :usage, :id, :model, :stop_reason, :stop_sequence, :type
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Mock
|
|
8
|
+
module Messages
|
|
9
|
+
# Base class for Mock messages.
|
|
10
|
+
class Base < Common::BaseModel
|
|
11
|
+
attribute :role, :string
|
|
12
|
+
attribute :content
|
|
13
|
+
|
|
14
|
+
validates :role, presence: true
|
|
15
|
+
|
|
16
|
+
# Define content setter methods for different content types
|
|
17
|
+
%i[text image document].each do |content_type|
|
|
18
|
+
define_method(:"#{content_type}=") do |value|
|
|
19
|
+
# For mock provider, we keep content simple
|
|
20
|
+
# If it's text, just set content to the text value
|
|
21
|
+
if content_type == :text
|
|
22
|
+
self.content = value
|
|
23
|
+
else
|
|
24
|
+
# For image/document, MockProvider doesn't support these, so ignore
|
|
25
|
+
# (or could raise an error)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Converts to common format.
|
|
31
|
+
#
|
|
32
|
+
# @return [Hash] message in canonical format with role and text content
|
|
33
|
+
def to_common
|
|
34
|
+
{
|
|
35
|
+
role: role,
|
|
36
|
+
content: extract_text_content,
|
|
37
|
+
name: nil
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# Extracts text content from the content structure.
|
|
44
|
+
#
|
|
45
|
+
# @return [String] extracted text content
|
|
46
|
+
def extract_text_content
|
|
47
|
+
case content
|
|
48
|
+
when String
|
|
49
|
+
content
|
|
50
|
+
when Array
|
|
51
|
+
# Join all text blocks
|
|
52
|
+
content.select { |block| block.is_a?(Hash) && block[:type] == "text" }
|
|
53
|
+
.map { |block| block[:text] }
|
|
54
|
+
.join("\n")
|
|
55
|
+
else
|
|
56
|
+
content.to_s
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Mock
|
|
8
|
+
module Messages
|
|
9
|
+
# User message for Mock provider.
|
|
10
|
+
class User < Base
|
|
11
|
+
attribute :role, :string, as: "user"
|
|
12
|
+
|
|
13
|
+
validates :content, presence: true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Mock
|
|
8
|
+
# Configuration options for the Mock provider.
|
|
9
|
+
#
|
|
10
|
+
# This provider doesn't make real API calls, so most options are unused.
|
|
11
|
+
# Included for consistency with other providers.
|
|
12
|
+
class Options < Common::BaseModel
|
|
13
|
+
attribute :base_url, :string, default: "https://mock.example.com"
|
|
14
|
+
attribute :api_key, :string, default: "mock-api-key"
|
|
15
|
+
|
|
16
|
+
# Common Interface Compatibility
|
|
17
|
+
alias_attribute :access_token, :api_key
|
|
18
|
+
|
|
19
|
+
def initialize(kwargs = {})
|
|
20
|
+
kwargs = kwargs.deep_symbolize_keys if kwargs.respond_to?(:deep_symbolize_keys)
|
|
21
|
+
super(**deep_compact(kwargs))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def extra_headers
|
|
25
|
+
{}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/providers/common/model"
|
|
4
|
+
|
|
5
|
+
require_relative "messages/_types"
|
|
6
|
+
|
|
7
|
+
module ActiveAgent
|
|
8
|
+
module Providers
|
|
9
|
+
module Mock
|
|
10
|
+
# Request model for Mock provider.
|
|
11
|
+
#
|
|
12
|
+
# Simplified request model that accepts messages and basic parameters.
|
|
13
|
+
class Request < Common::BaseModel
|
|
14
|
+
# Required parameters
|
|
15
|
+
attribute :model, :string, default: "mock-model"
|
|
16
|
+
attribute :messages, Messages::MessagesType.new
|
|
17
|
+
|
|
18
|
+
# Optional parameters
|
|
19
|
+
attribute :instructions # System instructions
|
|
20
|
+
attribute :temperature, :float
|
|
21
|
+
attribute :max_tokens, :integer
|
|
22
|
+
attribute :stream, :boolean, default: false
|
|
23
|
+
attribute :tools # Array of tool definitions
|
|
24
|
+
attribute :tool_choice # Tool choice configuration
|
|
25
|
+
|
|
26
|
+
# Common Format Compatibility
|
|
27
|
+
def message=(value)
|
|
28
|
+
self.messages ||= []
|
|
29
|
+
self.messages << value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def response_format
|
|
33
|
+
{ type: "text" }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "_base_provider"
|
|
4
|
+
require_relative "mock/_types"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Providers
|
|
8
|
+
# Mock provider for testing purposes.
|
|
9
|
+
#
|
|
10
|
+
# This provider doesn't make real API calls. Instead, it returns the last
|
|
11
|
+
# message content converted to pig latin for prompts, and random data for embeddings.
|
|
12
|
+
# Useful for testing without incurring API costs or requiring network access.
|
|
13
|
+
#
|
|
14
|
+
# @example Basic usage
|
|
15
|
+
# provider = ActiveAgent::Providers::MockProvider.new(...)
|
|
16
|
+
# result = provider.prompt
|
|
17
|
+
#
|
|
18
|
+
# @see BaseProvider
|
|
19
|
+
class MockProvider < BaseProvider
|
|
20
|
+
# Returns the embedding request type for Mock.
|
|
21
|
+
#
|
|
22
|
+
# @return [ActiveModel::Type::Value] The Mock embedding request type
|
|
23
|
+
def self.embed_request_type
|
|
24
|
+
Mock::EmbeddingRequestType.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns a mock client (just returns self since we don't need a real client).
|
|
28
|
+
#
|
|
29
|
+
# @return [MockProvider] Returns self
|
|
30
|
+
def client
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
# Executes a mock prompt request.
|
|
37
|
+
#
|
|
38
|
+
# Extracts the last user message, converts it to pig latin, and returns
|
|
39
|
+
# a mock response structure. Handles both streaming and non-streaming.
|
|
40
|
+
#
|
|
41
|
+
# @param parameters [Hash] The prompt request parameters
|
|
42
|
+
# @return [Hash] A mock API response structure
|
|
43
|
+
def api_prompt_execute(parameters)
|
|
44
|
+
# Extract the last message content
|
|
45
|
+
last_message = [ request.instructions, parameters[:messages]&.last&.dig(:content) ].compact.join(" ")
|
|
46
|
+
content = extract_message_content(last_message)
|
|
47
|
+
|
|
48
|
+
# Convert to pig latin
|
|
49
|
+
pig_latin_content = to_pig_latin(content)
|
|
50
|
+
|
|
51
|
+
if parameters[:stream]
|
|
52
|
+
# For streaming, call the stream proc with chunks
|
|
53
|
+
stream_proc = parameters[:stream]
|
|
54
|
+
simulate_streaming(pig_latin_content, stream_proc)
|
|
55
|
+
nil
|
|
56
|
+
else
|
|
57
|
+
# Return a complete response
|
|
58
|
+
{
|
|
59
|
+
id: "mock-#{SecureRandom.hex(8)}",
|
|
60
|
+
type: "message",
|
|
61
|
+
role: "assistant",
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: pig_latin_content
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
model: parameters[:model] || "mock-model",
|
|
69
|
+
stop_reason: "end_turn",
|
|
70
|
+
usage: {
|
|
71
|
+
input_tokens: content.length,
|
|
72
|
+
output_tokens: pig_latin_content.length
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Executes a mock embedding request.
|
|
79
|
+
#
|
|
80
|
+
# Returns random embedding vectors for testing purposes.
|
|
81
|
+
#
|
|
82
|
+
# @param parameters [Hash] The embedding request parameters
|
|
83
|
+
# @return [Hash] A mock embedding response structure
|
|
84
|
+
def api_embed_execute(parameters)
|
|
85
|
+
input = parameters[:input]
|
|
86
|
+
inputs = input.is_a?(Array) ? input : [ input ]
|
|
87
|
+
dimensions = parameters[:dimensions] || 1536
|
|
88
|
+
|
|
89
|
+
{
|
|
90
|
+
object: "list",
|
|
91
|
+
data: inputs.map.with_index do |text, index|
|
|
92
|
+
{
|
|
93
|
+
object: "embedding",
|
|
94
|
+
index: index,
|
|
95
|
+
embedding: generate_random_embedding(dimensions)
|
|
96
|
+
}
|
|
97
|
+
end,
|
|
98
|
+
model: parameters[:model] || "mock-embedding-model",
|
|
99
|
+
usage: {
|
|
100
|
+
prompt_tokens: inputs.sum { |text| text.to_s.length },
|
|
101
|
+
total_tokens: inputs.sum { |text| text.to_s.length }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Processes streaming response chunks.
|
|
107
|
+
#
|
|
108
|
+
# Handles mock streaming chunks, similar to real provider implementations.
|
|
109
|
+
#
|
|
110
|
+
# @param api_response_chunk [Hash] The streaming response chunk
|
|
111
|
+
# @return [void]
|
|
112
|
+
def process_stream_chunk(api_response_chunk)
|
|
113
|
+
chunk_type = api_response_chunk[:type]&.to_sym
|
|
114
|
+
|
|
115
|
+
instrument("stream_chunk_processing.provider.active_agent", chunk_type: chunk_type)
|
|
116
|
+
|
|
117
|
+
broadcast_stream_open
|
|
118
|
+
|
|
119
|
+
case chunk_type
|
|
120
|
+
when :message_start
|
|
121
|
+
api_message = api_response_chunk[:message]
|
|
122
|
+
message_stack.push(api_message)
|
|
123
|
+
broadcast_stream_update(message_stack.last)
|
|
124
|
+
|
|
125
|
+
when :content_block_start
|
|
126
|
+
api_content = api_response_chunk[:content_block]
|
|
127
|
+
message_stack.last[:content] ||= []
|
|
128
|
+
message_stack.last[:content].push(api_content)
|
|
129
|
+
broadcast_stream_update(message_stack.last, api_content[:text])
|
|
130
|
+
|
|
131
|
+
when :content_block_delta
|
|
132
|
+
index = api_response_chunk[:index]
|
|
133
|
+
content = message_stack.last[:content][index]
|
|
134
|
+
delta = api_response_chunk[:delta]
|
|
135
|
+
|
|
136
|
+
if delta[:type] == "text_delta"
|
|
137
|
+
content[:text] ||= ""
|
|
138
|
+
content[:text] += delta[:text]
|
|
139
|
+
broadcast_stream_update(message_stack.last, delta[:text])
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
when :message_delta
|
|
143
|
+
delta = api_response_chunk[:delta]
|
|
144
|
+
message_stack.last[:stop_reason] = delta[:stop_reason] if delta[:stop_reason]
|
|
145
|
+
|
|
146
|
+
when :message_stop
|
|
147
|
+
# Stream complete
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Extracts messages from API response.
|
|
152
|
+
#
|
|
153
|
+
# @param api_response [Hash] The API response
|
|
154
|
+
# @return [Array<Hash>] Array of message hashes
|
|
155
|
+
def process_prompt_finished_extract_messages(api_response)
|
|
156
|
+
return nil if api_response.nil? # Streaming case
|
|
157
|
+
[ api_response ]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Extracts function calls from API response.
|
|
161
|
+
#
|
|
162
|
+
# Mock provider doesn't support tool calling by default.
|
|
163
|
+
#
|
|
164
|
+
# @return [nil]
|
|
165
|
+
def process_prompt_finished_extract_function_calls
|
|
166
|
+
nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
# Extracts text content from a message.
|
|
172
|
+
#
|
|
173
|
+
# @param message [Hash, String, nil] The message to extract from
|
|
174
|
+
# @return [String] The extracted text content
|
|
175
|
+
def extract_message_content(message)
|
|
176
|
+
return "" if message.nil?
|
|
177
|
+
|
|
178
|
+
case message
|
|
179
|
+
when String
|
|
180
|
+
message
|
|
181
|
+
when Hash
|
|
182
|
+
if message[:content].is_a?(String)
|
|
183
|
+
message[:content]
|
|
184
|
+
elsif message[:content].is_a?(Array)
|
|
185
|
+
message[:content]
|
|
186
|
+
.select { |block| block.is_a?(Hash) && block[:type] == "text" }
|
|
187
|
+
.map { |block| block[:text] }
|
|
188
|
+
.join(" ")
|
|
189
|
+
else
|
|
190
|
+
message[:content].to_s
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
message.to_s
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Converts text to pig latin.
|
|
198
|
+
#
|
|
199
|
+
# Simple pig latin conversion:
|
|
200
|
+
# - Words starting with vowels: add "way" to the end
|
|
201
|
+
# - Words starting with consonants: move consonants to end and add "ay"
|
|
202
|
+
# - Preserves punctuation and capitalization
|
|
203
|
+
#
|
|
204
|
+
# @param text [String] The text to convert
|
|
205
|
+
# @return [String] The text in pig latin
|
|
206
|
+
def to_pig_latin(text)
|
|
207
|
+
return "" if text.nil? || text.empty?
|
|
208
|
+
|
|
209
|
+
words = text.split(/\b/)
|
|
210
|
+
|
|
211
|
+
words.map do |word|
|
|
212
|
+
# Skip non-word characters (spaces, punctuation, etc.)
|
|
213
|
+
next word unless word.match?(/\w/)
|
|
214
|
+
|
|
215
|
+
# Check if word starts with a vowel
|
|
216
|
+
if word.match?(/^[aeiouAEIOU]/)
|
|
217
|
+
"#{word}way"
|
|
218
|
+
else
|
|
219
|
+
# Find the first vowel
|
|
220
|
+
match = word.match(/^([^aeiouAEIOU]+)(.*)/)
|
|
221
|
+
if match
|
|
222
|
+
consonants = match[1]
|
|
223
|
+
rest = match[2]
|
|
224
|
+
|
|
225
|
+
# Preserve capitalization
|
|
226
|
+
if word[0] == word[0].upcase && rest.length > 0
|
|
227
|
+
"#{rest[0].upcase}#{rest[1..-1]}#{consonants.downcase}ay"
|
|
228
|
+
else
|
|
229
|
+
"#{rest}#{consonants}ay"
|
|
230
|
+
end
|
|
231
|
+
else
|
|
232
|
+
# No vowels found, just add "ay"
|
|
233
|
+
"#{word}ay"
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end.join
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Simulates streaming by sending chunks.
|
|
240
|
+
#
|
|
241
|
+
# @param content [String] The full content to stream
|
|
242
|
+
# @param stream_proc [Proc] The streaming callback
|
|
243
|
+
# @return [void]
|
|
244
|
+
def simulate_streaming(content, stream_proc)
|
|
245
|
+
message_id = "mock-#{SecureRandom.hex(8)}"
|
|
246
|
+
|
|
247
|
+
# Send message_start
|
|
248
|
+
stream_proc.call({
|
|
249
|
+
type: :message_start,
|
|
250
|
+
message: {
|
|
251
|
+
id: message_id,
|
|
252
|
+
type: "message",
|
|
253
|
+
role: "assistant",
|
|
254
|
+
content: [],
|
|
255
|
+
model: "mock-model"
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
# Send content_block_start
|
|
260
|
+
stream_proc.call({
|
|
261
|
+
type: :content_block_start,
|
|
262
|
+
index: 0,
|
|
263
|
+
content_block: {
|
|
264
|
+
type: "text",
|
|
265
|
+
text: ""
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
# Send content in chunks (simulate word-by-word streaming)
|
|
270
|
+
words = content.split(" ")
|
|
271
|
+
words.each_with_index do |word, i|
|
|
272
|
+
text_chunk = i == 0 ? word : " #{word}"
|
|
273
|
+
stream_proc.call({
|
|
274
|
+
type: :content_block_delta,
|
|
275
|
+
index: 0,
|
|
276
|
+
delta: {
|
|
277
|
+
type: "text_delta",
|
|
278
|
+
text: text_chunk
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Send message_delta with stop_reason
|
|
284
|
+
stream_proc.call({
|
|
285
|
+
type: :message_delta,
|
|
286
|
+
delta: {
|
|
287
|
+
stop_reason: "end_turn"
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
# Send message_stop
|
|
292
|
+
stream_proc.call({
|
|
293
|
+
type: :message_stop
|
|
294
|
+
})
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Generates a random embedding vector.
|
|
298
|
+
#
|
|
299
|
+
# @param dimensions [Integer] The number of dimensions for the embedding
|
|
300
|
+
# @return [Array<Float>] A random normalized vector
|
|
301
|
+
def generate_random_embedding(dimensions)
|
|
302
|
+
# Generate random values between -1 and 1
|
|
303
|
+
vector = Array.new(dimensions) { rand * 2 - 1 }
|
|
304
|
+
|
|
305
|
+
# Normalize the vector to unit length (common for embeddings)
|
|
306
|
+
magnitude = Math.sqrt(vector.sum { |v| v ** 2 })
|
|
307
|
+
vector.map { |v| v / magnitude }
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|