activeagent 1.0.0.rc1 → 1.0.0
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 +31 -1
- data/lib/active_agent/providers/_base_provider.rb +92 -82
- data/lib/active_agent/providers/anthropic/_types.rb +2 -2
- data/lib/active_agent/providers/anthropic/request.rb +135 -81
- data/lib/active_agent/providers/anthropic/transforms.rb +353 -0
- data/lib/active_agent/providers/anthropic_provider.rb +96 -53
- data/lib/active_agent/providers/common/messages/_types.rb +37 -1
- data/lib/active_agent/providers/common/responses/base.rb +118 -70
- data/lib/active_agent/providers/common/usage.rb +385 -0
- data/lib/active_agent/providers/concerns/instrumentation.rb +263 -0
- data/lib/active_agent/providers/log_subscriber.rb +64 -246
- data/lib/active_agent/providers/mock_provider.rb +23 -23
- data/lib/active_agent/providers/ollama/chat/request.rb +214 -35
- data/lib/active_agent/providers/ollama/chat/transforms.rb +135 -0
- data/lib/active_agent/providers/ollama/embedding/request.rb +160 -47
- data/lib/active_agent/providers/ollama/embedding/transforms.rb +160 -0
- data/lib/active_agent/providers/ollama_provider.rb +0 -1
- data/lib/active_agent/providers/open_ai/_base.rb +3 -2
- data/lib/active_agent/providers/open_ai/chat/_types.rb +13 -1
- data/lib/active_agent/providers/open_ai/chat/request.rb +132 -186
- data/lib/active_agent/providers/open_ai/chat/transforms.rb +364 -0
- data/lib/active_agent/providers/open_ai/chat_provider.rb +57 -36
- data/lib/active_agent/providers/open_ai/embedding/_types.rb +13 -2
- data/lib/active_agent/providers/open_ai/embedding/request.rb +38 -70
- data/lib/active_agent/providers/open_ai/embedding/transforms.rb +88 -0
- data/lib/active_agent/providers/open_ai/responses/_types.rb +1 -7
- data/lib/active_agent/providers/open_ai/responses/request.rb +100 -134
- data/lib/active_agent/providers/open_ai/responses/transforms.rb +228 -0
- data/lib/active_agent/providers/open_ai/responses_provider.rb +77 -30
- data/lib/active_agent/providers/open_ai_provider.rb +0 -3
- data/lib/active_agent/providers/open_router/_types.rb +27 -1
- data/lib/active_agent/providers/open_router/options.rb +49 -1
- data/lib/active_agent/providers/open_router/request.rb +232 -66
- data/lib/active_agent/providers/open_router/requests/_types.rb +0 -1
- data/lib/active_agent/providers/open_router/requests/messages/_types.rb +37 -40
- data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +19 -3
- data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +15 -4
- data/lib/active_agent/providers/open_router/requests/plugin.rb +19 -3
- data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +30 -8
- data/lib/active_agent/providers/open_router/requests/prediction.rb +17 -0
- data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +41 -7
- data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +60 -19
- data/lib/active_agent/providers/open_router/requests/response_format.rb +30 -2
- data/lib/active_agent/providers/open_router/transforms.rb +134 -0
- data/lib/active_agent/providers/open_router_provider.rb +9 -0
- data/lib/active_agent/version.rb +1 -1
- metadata +15 -159
- data/lib/active_agent/generation_provider/open_router/types.rb +0 -505
- data/lib/active_agent/generation_provider/xai_provider.rb +0 -144
- data/lib/active_agent/providers/anthropic/requests/_types.rb +0 -190
- data/lib/active_agent/providers/anthropic/requests/container_params.rb +0 -19
- data/lib/active_agent/providers/anthropic/requests/content/base.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/content/sources/base.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/context_management_config.rb +0 -18
- data/lib/active_agent/providers/anthropic/requests/messages/_types.rb +0 -189
- data/lib/active_agent/providers/anthropic/requests/messages/assistant.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/base.rb +0 -63
- data/lib/active_agent/providers/anthropic/requests/messages/content/_types.rb +0 -143
- data/lib/active_agent/providers/anthropic/requests/messages/content/base.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/messages/content/document.rb +0 -26
- data/lib/active_agent/providers/anthropic/requests/messages/content/image.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/redacted_thinking.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/messages/content/search_result.rb +0 -27
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/_types.rb +0 -171
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/base.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_base64.rb +0 -25
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_file.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_text.rb +0 -25
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_url.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_base64.rb +0 -27
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_file.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_url.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/text.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/messages/content/thinking.rb +0 -23
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_result.rb +0 -24
- data/lib/active_agent/providers/anthropic/requests/messages/content/tool_use.rb +0 -28
- data/lib/active_agent/providers/anthropic/requests/messages/user.rb +0 -21
- data/lib/active_agent/providers/anthropic/requests/metadata.rb +0 -18
- data/lib/active_agent/providers/anthropic/requests/response_format.rb +0 -22
- data/lib/active_agent/providers/anthropic/requests/thinking_config/_types.rb +0 -60
- data/lib/active_agent/providers/anthropic/requests/thinking_config/base.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/thinking_config/disabled.rb +0 -16
- data/lib/active_agent/providers/anthropic/requests/thinking_config/enabled.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/tool_choice/_types.rb +0 -78
- data/lib/active_agent/providers/anthropic/requests/tool_choice/any.rb +0 -17
- data/lib/active_agent/providers/anthropic/requests/tool_choice/auto.rb +0 -17
- data/lib/active_agent/providers/anthropic/requests/tool_choice/base.rb +0 -20
- data/lib/active_agent/providers/anthropic/requests/tool_choice/none.rb +0 -16
- data/lib/active_agent/providers/anthropic/requests/tool_choice/tool.rb +0 -20
- data/lib/active_agent/providers/ollama/chat/requests/_types.rb +0 -3
- data/lib/active_agent/providers/ollama/chat/requests/messages/_types.rb +0 -116
- data/lib/active_agent/providers/ollama/chat/requests/messages/assistant.rb +0 -19
- data/lib/active_agent/providers/ollama/chat/requests/messages/user.rb +0 -19
- data/lib/active_agent/providers/ollama/embedding/requests/_types.rb +0 -83
- data/lib/active_agent/providers/ollama/embedding/requests/options.rb +0 -104
- data/lib/active_agent/providers/open_ai/chat/requests/_types.rb +0 -229
- data/lib/active_agent/providers/open_ai/chat/requests/audio.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/messages/_types.rb +0 -123
- data/lib/active_agent/providers/open_ai/chat/requests/messages/assistant.rb +0 -42
- data/lib/active_agent/providers/open_ai/chat/requests/messages/base.rb +0 -78
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/_types.rb +0 -133
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/audio.rb +0 -35
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/base.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/file.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/_types.rb +0 -60
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/details.rb +0 -41
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/image.rb +0 -37
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/refusal.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/content/text.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/developer.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/function.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/system.rb +0 -25
- data/lib/active_agent/providers/open_ai/chat/requests/messages/tool.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/messages/user.rb +0 -32
- data/lib/active_agent/providers/open_ai/chat/requests/prediction.rb +0 -46
- data/lib/active_agent/providers/open_ai/chat/requests/response_format.rb +0 -53
- data/lib/active_agent/providers/open_ai/chat/requests/stream_options.rb +0 -24
- data/lib/active_agent/providers/open_ai/chat/requests/tool_choice.rb +0 -26
- data/lib/active_agent/providers/open_ai/chat/requests/tools/_types.rb +0 -5
- data/lib/active_agent/providers/open_ai/chat/requests/tools/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/chat/requests/tools/custom_tool.rb +0 -41
- data/lib/active_agent/providers/open_ai/chat/requests/tools/function_tool.rb +0 -51
- data/lib/active_agent/providers/open_ai/chat/requests/web_search_options.rb +0 -45
- data/lib/active_agent/providers/open_ai/embedding/requests/_types.rb +0 -49
- data/lib/active_agent/providers/open_ai/responses/requests/_types.rb +0 -231
- data/lib/active_agent/providers/open_ai/responses/requests/conversation.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/_types.rb +0 -264
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/assistant_message.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/base.rb +0 -89
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb +0 -30
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/_types.rb +0 -207
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_audio.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_file.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_image.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_text.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call_output.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/developer_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/file_search_tool_call.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_call_output.rb +0 -32
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_tool_call.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/image_gen_tool_call.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/input_message.rb +0 -31
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/item_reference.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call_output.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_request.rb +0 -30
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_response.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_list_tools.rb +0 -29
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_tool_call.rb +0 -35
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/output_message.rb +0 -35
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/reasoning.rb +0 -33
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/system_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_call_base.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_message.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/user_message.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/inputs/web_search_tool_call.rb +0 -24
- data/lib/active_agent/providers/open_ai/responses/requests/prompt_reference.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/reasoning.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/stream_options.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text/_types.rb +0 -89
- data/lib/active_agent/providers/open_ai/responses/requests/text/base.rb +0 -22
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_object.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text/json_schema.rb +0 -48
- data/lib/active_agent/providers/open_ai/responses/requests/text/plain.rb +0 -20
- data/lib/active_agent/providers/open_ai/responses/requests/text.rb +0 -41
- data/lib/active_agent/providers/open_ai/responses/requests/tool_choice.rb +0 -26
- data/lib/active_agent/providers/open_ai/responses/requests/tools/_types.rb +0 -112
- data/lib/active_agent/providers/open_ai/responses/requests/tools/base.rb +0 -25
- data/lib/active_agent/providers/open_ai/responses/requests/tools/code_interpreter_tool.rb +0 -23
- data/lib/active_agent/providers/open_ai/responses/requests/tools/computer_tool.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/tools/custom_tool.rb +0 -28
- data/lib/active_agent/providers/open_ai/responses/requests/tools/file_search_tool.rb +0 -27
- data/lib/active_agent/providers/open_ai/responses/requests/tools/function_tool.rb +0 -29
- data/lib/active_agent/providers/open_ai/responses/requests/tools/image_generation_tool.rb +0 -37
- data/lib/active_agent/providers/open_ai/responses/requests/tools/local_shell_tool.rb +0 -21
- data/lib/active_agent/providers/open_ai/responses/requests/tools/mcp_tool.rb +0 -41
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_preview_tool.rb +0 -24
- data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_tool.rb +0 -25
- data/lib/active_agent/providers/open_ai/schema.yml +0 -65937
- data/lib/active_agent/providers/open_router/requests/message.rb +0 -1
- data/lib/active_agent/providers/open_router/requests/messages/assistant.rb +0 -20
- data/lib/active_agent/providers/open_router/requests/messages/user.rb +0 -30
|
@@ -1,81 +1,247 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "delegate"
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "transforms"
|
|
4
6
|
require_relative "requests/_types"
|
|
5
7
|
|
|
6
8
|
module ActiveAgent
|
|
7
9
|
module Providers
|
|
8
10
|
module OpenRouter
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
#
|
|
11
|
+
# Wraps OpenAI gem's CompletionCreateParams with OpenRouter-specific extensions
|
|
12
|
+
#
|
|
13
|
+
# Delegates to OpenAI::Models::Chat::CompletionCreateParams for OpenAI-compatible
|
|
14
|
+
# parameters while adding support for OpenRouter-specific features like plugins,
|
|
15
|
+
# provider preferences, model fallbacks, and extended sampling parameters.
|
|
16
|
+
#
|
|
17
|
+
# OpenRouter-specific parameters:
|
|
18
|
+
# - plugins: Array of plugin configurations (e.g., file-parser for PDFs)
|
|
19
|
+
# - provider: ProviderPreferences object with require_parameters, data_collection, etc.
|
|
20
|
+
# - transforms: Array of transformation strings
|
|
21
|
+
# - models: Array of model strings for fallback routing
|
|
22
|
+
# - route: Routing strategy (default: "fallback")
|
|
23
|
+
# - top_k, min_p, top_a, repetition_penalty: Extended sampling parameters
|
|
24
|
+
#
|
|
25
|
+
# @example Basic usage
|
|
26
|
+
# request = Request.new(
|
|
27
|
+
# model: "openai/gpt-4",
|
|
28
|
+
# messages: [{role: "user", content: "Hello"}]
|
|
29
|
+
# )
|
|
30
|
+
#
|
|
31
|
+
# @example With OpenRouter-specific features
|
|
32
|
+
# request = Request.new(
|
|
33
|
+
# model: "openai/gpt-4",
|
|
34
|
+
# messages: [{role: "user", content: "Hello"}],
|
|
35
|
+
# models: ["anthropic/claude-3", "openai/gpt-4"],
|
|
36
|
+
# provider: {require_parameters: true}
|
|
37
|
+
# )
|
|
38
|
+
class Request < SimpleDelegator
|
|
39
|
+
# Default parameter values
|
|
40
|
+
DEFAULTS = {
|
|
41
|
+
frequency_penalty: 0,
|
|
42
|
+
logprobs: false,
|
|
43
|
+
n: 1,
|
|
44
|
+
presence_penalty: 0,
|
|
45
|
+
temperature: 1,
|
|
46
|
+
top_p: 1,
|
|
47
|
+
route: "fallback",
|
|
48
|
+
models: [],
|
|
49
|
+
transforms: []
|
|
50
|
+
}.freeze
|
|
51
|
+
|
|
52
|
+
# @return [Boolean, nil]
|
|
53
|
+
attr_reader :stream
|
|
54
|
+
|
|
55
|
+
# @return [Hash] OpenRouter-specific parameters
|
|
56
|
+
attr_reader :openrouter_params
|
|
57
|
+
|
|
58
|
+
# Creates a new OpenRouter request
|
|
59
|
+
#
|
|
60
|
+
# @param params [Hash] request parameters
|
|
61
|
+
# @option params [String] :model model identifier (default: "openrouter/auto")
|
|
62
|
+
# @option params [Array, String, Hash] :messages required conversation messages
|
|
63
|
+
# @option params [Array] :plugins plugin configurations
|
|
64
|
+
# @option params [Hash] :provider provider preferences
|
|
65
|
+
# @option params [Array<String>] :transforms transformation strings
|
|
66
|
+
# @option params [Array<String>] :models fallback model list
|
|
67
|
+
# @option params [String] :route routing strategy
|
|
68
|
+
# @option params [Integer] :top_k sampling parameter
|
|
69
|
+
# @option params [Float] :min_p minimum probability sampling
|
|
70
|
+
# @option params [Float] :top_a top-a sampling
|
|
71
|
+
# @option params [Float] :repetition_penalty repetition penalty
|
|
72
|
+
# @raise [ArgumentError] when parameters are invalid
|
|
73
|
+
def initialize(**params)
|
|
74
|
+
# Step 1: Extract stream flag
|
|
75
|
+
@stream = params[:stream]
|
|
76
|
+
|
|
77
|
+
# Step 2: Apply defaults
|
|
78
|
+
params = apply_defaults(params)
|
|
79
|
+
|
|
80
|
+
# Step 3: Normalize parameters and split into OpenAI vs OpenRouter-specific
|
|
81
|
+
# This handles response_format special logic for structured output
|
|
82
|
+
openai_params, @openrouter_params = Transforms.normalize_params(params)
|
|
83
|
+
|
|
84
|
+
# Step 4: Create gem model with OpenAI-compatible params
|
|
85
|
+
gem_model = ::OpenAI::Models::Chat::CompletionCreateParams.new(**openai_params)
|
|
86
|
+
|
|
87
|
+
# Step 5: Delegate to the gem model
|
|
88
|
+
super(gem_model)
|
|
89
|
+
rescue ArgumentError => e
|
|
90
|
+
raise ArgumentError, "Invalid OpenRouter request parameters: #{e.message}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Serializes request for API submission
|
|
94
|
+
#
|
|
95
|
+
# Merges OpenAI-compatible parameters with OpenRouter-specific extensions.
|
|
96
|
+
#
|
|
97
|
+
# @return [Hash] cleaned request hash
|
|
98
|
+
def serialize
|
|
99
|
+
# Get OpenAI params from gem model
|
|
100
|
+
openai_hash = Transforms.gem_to_hash(__getobj__)
|
|
101
|
+
|
|
102
|
+
# Merge with OpenRouter-specific params
|
|
103
|
+
Transforms.cleanup_serialized_request(openai_hash, @openrouter_params, DEFAULTS, __getobj__)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @return [Array<Hash>, nil]
|
|
107
|
+
def messages
|
|
108
|
+
__getobj__.instance_variable_get(:@data)[:messages]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Sets messages with normalization
|
|
112
|
+
#
|
|
113
|
+
# Merges new messages with existing ones for compatibility.
|
|
114
|
+
#
|
|
115
|
+
# @param value [Array, String, Hash]
|
|
116
|
+
# @return [void]
|
|
62
117
|
def messages=(value)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
118
|
+
normalized_value = Transforms.normalize_messages(value)
|
|
119
|
+
current_messages = messages || []
|
|
120
|
+
|
|
121
|
+
# Merge behavior for OpenRouter compatibility
|
|
122
|
+
merged = current_messages | Array(normalized_value)
|
|
123
|
+
__getobj__.instance_variable_get(:@data)[:messages] = merged
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Alias for messages (common format compatibility)
|
|
127
|
+
#
|
|
128
|
+
# @return [Array<Hash>, nil]
|
|
129
|
+
def message
|
|
130
|
+
messages
|
|
69
131
|
end
|
|
70
132
|
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
133
|
+
# @param value [Array, String, Hash]
|
|
134
|
+
# @return [void]
|
|
135
|
+
def message=(value)
|
|
136
|
+
self.messages = value
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Sets instructions as developer messages
|
|
140
|
+
#
|
|
141
|
+
# Prepends developer messages to the messages array.
|
|
142
|
+
#
|
|
143
|
+
# @param values [Array<String>, String]
|
|
144
|
+
# @return [void]
|
|
145
|
+
def instructions=(*values)
|
|
146
|
+
instructions_messages = OpenAI::Chat::Transforms.normalize_instructions(values.flatten)
|
|
147
|
+
current_messages = messages || []
|
|
148
|
+
self.messages = instructions_messages + current_messages
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Accessor for OpenRouter-specific provider preferences
|
|
152
|
+
#
|
|
153
|
+
# @return [Hash, nil]
|
|
154
|
+
def provider
|
|
155
|
+
@openrouter_params[:provider]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Sets provider preferences
|
|
159
|
+
#
|
|
160
|
+
# @param value [Hash]
|
|
161
|
+
# @return [void]
|
|
162
|
+
def provider=(value)
|
|
163
|
+
@openrouter_params[:provider] = value
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Accessor for OpenRouter plugins
|
|
167
|
+
#
|
|
168
|
+
# @return [Array, nil]
|
|
169
|
+
def plugins
|
|
170
|
+
@openrouter_params[:plugins]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Sets plugins
|
|
174
|
+
#
|
|
175
|
+
# @param value [Array]
|
|
176
|
+
# @return [void]
|
|
177
|
+
def plugins=(value)
|
|
178
|
+
@openrouter_params[:plugins] = value
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Accessor for OpenRouter transforms
|
|
182
|
+
#
|
|
183
|
+
# @return [Array]
|
|
184
|
+
def transforms
|
|
185
|
+
@openrouter_params[:transforms] || []
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Sets transforms
|
|
189
|
+
#
|
|
190
|
+
# @param value [Array]
|
|
191
|
+
# @return [void]
|
|
192
|
+
def transforms=(value)
|
|
193
|
+
@openrouter_params[:transforms] = value
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Accessor for fallback models
|
|
197
|
+
#
|
|
198
|
+
# @return [Array]
|
|
199
|
+
def models
|
|
200
|
+
@openrouter_params[:models] || []
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Sets fallback models
|
|
204
|
+
#
|
|
205
|
+
# @param value [Array]
|
|
206
|
+
# @return [void]
|
|
207
|
+
def models=(value)
|
|
208
|
+
@openrouter_params[:models] = value
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Alias for backwards compatibility
|
|
212
|
+
alias_method :fallback_models, :models
|
|
213
|
+
alias_method :fallback_models=, :models=
|
|
214
|
+
|
|
215
|
+
# Accessor for routing strategy
|
|
216
|
+
#
|
|
217
|
+
# @return [String]
|
|
218
|
+
def route
|
|
219
|
+
@openrouter_params[:route] || DEFAULTS[:route]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Sets routing strategy
|
|
223
|
+
#
|
|
224
|
+
# @param value [String]
|
|
225
|
+
# @return [void]
|
|
226
|
+
def route=(value)
|
|
227
|
+
@openrouter_params[:route] = value
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
|
|
232
|
+
# @api private
|
|
233
|
+
# @param params [Hash]
|
|
234
|
+
# @return [Hash]
|
|
235
|
+
def apply_defaults(params)
|
|
236
|
+
# Set default model if not provided
|
|
237
|
+
params[:model] ||= "openrouter/auto"
|
|
238
|
+
|
|
239
|
+
# Apply other defaults
|
|
240
|
+
DEFAULTS.each do |key, value|
|
|
241
|
+
params[key] = value unless params.key?(key)
|
|
76
242
|
end
|
|
77
243
|
|
|
78
|
-
|
|
244
|
+
params
|
|
79
245
|
end
|
|
80
246
|
end
|
|
81
247
|
end
|
|
@@ -1,55 +1,52 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require_relative "assistant"
|
|
6
|
-
require_relative "user"
|
|
3
|
+
require_relative "../../transforms"
|
|
7
4
|
|
|
8
5
|
module ActiveAgent
|
|
9
6
|
module Providers
|
|
10
7
|
module OpenRouter
|
|
11
8
|
module Requests
|
|
12
9
|
module Messages
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
# ActiveModel type for casting and normalizing messages
|
|
11
|
+
#
|
|
12
|
+
# Delegates to OpenRouter transforms which use OpenAI's message normalization.
|
|
13
|
+
class MessagesType < ActiveModel::Type::Value
|
|
14
|
+
# Casts value to normalized messages array
|
|
15
|
+
#
|
|
16
|
+
# @param value [Array, String, Hash, nil]
|
|
17
|
+
# @return [Array, nil]
|
|
18
|
+
def cast(value)
|
|
19
|
+
return nil if value.nil?
|
|
20
|
+
Transforms.normalize_messages(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Serializes messages to hash array
|
|
24
|
+
#
|
|
25
|
+
# @param value [Array, nil]
|
|
26
|
+
# @return [Array, nil]
|
|
27
|
+
def serialize(value)
|
|
28
|
+
return nil if value.nil?
|
|
29
|
+
|
|
30
|
+
# If already serialized as hashes, return as-is
|
|
31
|
+
return value if value.is_a?(Array) && value.all? { |m| m.is_a?(Hash) }
|
|
32
|
+
|
|
33
|
+
# Otherwise convert gem objects to hashes
|
|
34
|
+
value.map { |msg| Transforms.gem_to_hash(msg) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param value [Object]
|
|
38
|
+
# @return [Array, nil]
|
|
39
|
+
def deserialize(value)
|
|
40
|
+
cast(value)
|
|
18
41
|
end
|
|
19
42
|
end
|
|
20
43
|
|
|
21
|
-
|
|
44
|
+
# Kept for backwards compatibility but delegates to MessagesType
|
|
45
|
+
class MessageType < MessagesType
|
|
22
46
|
def cast(value)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
when String
|
|
27
|
-
User.new(content: value)
|
|
28
|
-
when Hash
|
|
29
|
-
hash = value.deep_symbolize_keys
|
|
30
|
-
role = hash[:role]&.to_sym
|
|
31
|
-
|
|
32
|
-
case role
|
|
33
|
-
when :developer
|
|
34
|
-
OpenAI::Chat::Requests::Messages::Developer.new(**hash)
|
|
35
|
-
when :system
|
|
36
|
-
OpenAI::Chat::Requests::Messages::System.new(**hash)
|
|
37
|
-
when :user, nil
|
|
38
|
-
User.new(**hash)
|
|
39
|
-
when :assistant
|
|
40
|
-
Assistant.new(**hash)
|
|
41
|
-
when :tool
|
|
42
|
-
OpenAI::Chat::Requests::Messages::Tool.new(**hash)
|
|
43
|
-
when :function
|
|
44
|
-
OpenAI::Chat::Requests::Messages::Function.new(**hash)
|
|
45
|
-
else
|
|
46
|
-
raise ArgumentError, "Unknown message role: #{role.inspect}"
|
|
47
|
-
end
|
|
48
|
-
when nil
|
|
49
|
-
nil
|
|
50
|
-
else
|
|
51
|
-
raise ArgumentError, "Cannot cast #{value.class} to Message (expected Base, String, Hash, or nil)"
|
|
52
|
-
end
|
|
47
|
+
# Single message - wrap in array then unwrap
|
|
48
|
+
result = super(value.is_a?(Array) ? value : [ value ])
|
|
49
|
+
result&.first
|
|
53
50
|
end
|
|
54
51
|
end
|
|
55
52
|
end
|
|
@@ -9,12 +9,28 @@ module ActiveAgent
|
|
|
9
9
|
module Requests
|
|
10
10
|
module Messages
|
|
11
11
|
module Content
|
|
12
|
-
# File content part for OpenRouter
|
|
12
|
+
# File content part for OpenRouter messages
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
14
|
+
# Represents a file attachment in a message. Unlike OpenAI which strips
|
|
15
|
+
# the data URI prefix, OpenRouter preserves it in the file_data field.
|
|
16
|
+
#
|
|
17
|
+
# @example PDF file attachment
|
|
18
|
+
# file = File.new(
|
|
19
|
+
# file: {
|
|
20
|
+
# file_data: 'data:application/pdf;base64,JVBERi0...',
|
|
21
|
+
# filename: 'document.pdf'
|
|
22
|
+
# }
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
# @see Files::Details
|
|
26
|
+
# @see https://openrouter.ai/docs/file-uploads OpenRouter File Uploads
|
|
16
27
|
class File < OpenAI::Chat::Requests::Messages::Content::Base
|
|
28
|
+
# @!attribute type
|
|
29
|
+
# @return [String] always "file"
|
|
17
30
|
attribute :type, :string, as: "file"
|
|
31
|
+
|
|
32
|
+
# @!attribute file
|
|
33
|
+
# @return [Files::Details] file details with data URI
|
|
18
34
|
attribute :file, Files::DetailsType.new
|
|
19
35
|
|
|
20
36
|
validates :file, presence: true
|
|
@@ -9,12 +9,23 @@ module ActiveAgent
|
|
|
9
9
|
module Messages
|
|
10
10
|
module Content
|
|
11
11
|
module Files
|
|
12
|
-
#
|
|
12
|
+
# File details for OpenRouter file attachments
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
# (e.g., data:application/pdf;base64,)
|
|
14
|
+
# Represents the nested file object within a file content part.
|
|
15
|
+
# Unlike OpenAI which strips the data URI prefix (e.g., data:application/pdf;base64,),
|
|
16
|
+
# OpenRouter requires it to be present in the file_data field.
|
|
17
|
+
#
|
|
18
|
+
# @example With data URI
|
|
19
|
+
# details = Details.new(
|
|
20
|
+
# file_data: 'data:application/pdf;base64,JVBERi0xLjQK...',
|
|
21
|
+
# filename: 'report.pdf'
|
|
22
|
+
# )
|
|
23
|
+
#
|
|
24
|
+
# @see Content::File
|
|
16
25
|
class Details < OpenAI::Chat::Requests::Messages::Content::Files::Details
|
|
17
|
-
#
|
|
26
|
+
# @!attribute file_data
|
|
27
|
+
# @return [String] file data with data URI prefix intact
|
|
28
|
+
# Format: "data:<mime-type>;base64,<base64-data>"
|
|
18
29
|
attribute :file_data, :string
|
|
19
30
|
end
|
|
20
31
|
end
|
|
@@ -4,16 +4,32 @@ module ActiveAgent
|
|
|
4
4
|
module Providers
|
|
5
5
|
module OpenRouter
|
|
6
6
|
module Requests
|
|
7
|
-
#
|
|
8
|
-
# Currently supports the file-parser plugin for PDF processing.
|
|
7
|
+
# Plugin configuration for OpenRouter requests
|
|
9
8
|
#
|
|
10
|
-
#
|
|
9
|
+
# OpenRouter supports plugins that enhance model capabilities.
|
|
10
|
+
# Currently supports the file-parser plugin for processing PDF documents.
|
|
11
|
+
#
|
|
12
|
+
# @example File parser plugin with PDF text extraction
|
|
11
13
|
# plugin = Plugin.new(
|
|
12
14
|
# id: 'file-parser',
|
|
13
15
|
# pdf: { engine: 'pdf-text' }
|
|
14
16
|
# )
|
|
17
|
+
#
|
|
18
|
+
# @example File parser plugin with OCR
|
|
19
|
+
# plugin = Plugin.new(
|
|
20
|
+
# id: 'file-parser',
|
|
21
|
+
# pdf: { engine: 'mistral-ocr' }
|
|
22
|
+
# )
|
|
23
|
+
#
|
|
24
|
+
# @see https://openrouter.ai/docs/plugins OpenRouter Plugins
|
|
25
|
+
# @see Plugins::PdfConfig
|
|
15
26
|
class Plugin < Common::BaseModel
|
|
27
|
+
# @!attribute id
|
|
28
|
+
# @return [String] plugin identifier (currently only 'file-parser' is supported)
|
|
16
29
|
attribute :id, :string
|
|
30
|
+
|
|
31
|
+
# @!attribute pdf
|
|
32
|
+
# @return [Plugins::PdfConfig, nil] PDF processing configuration
|
|
17
33
|
attribute :pdf, Plugins::PdfConfigType.new
|
|
18
34
|
|
|
19
35
|
validates :id, presence: true
|
|
@@ -5,19 +5,41 @@ module ActiveAgent
|
|
|
5
5
|
module OpenRouter
|
|
6
6
|
module Requests
|
|
7
7
|
module Plugins
|
|
8
|
-
#
|
|
8
|
+
# PDF processing configuration for file-parser plugin
|
|
9
9
|
#
|
|
10
|
-
# OpenRouter provides
|
|
11
|
-
#
|
|
12
|
-
# - "pdf-text": Best for well-structured PDFs with clear text content (Free)
|
|
13
|
-
# - "native": Only available for models that support file input natively (charged as input tokens)
|
|
10
|
+
# OpenRouter provides multiple PDF processing engines with different
|
|
11
|
+
# capabilities and costs:
|
|
14
12
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
13
|
+
# - **mistral-ocr**: Best for scanned documents or PDFs with images
|
|
14
|
+
# - Cost: $2 per 1,000 pages
|
|
15
|
+
# - Use when: Document is image-heavy or has poor text extraction
|
|
17
16
|
#
|
|
18
|
-
#
|
|
17
|
+
# - **pdf-text**: Best for well-structured PDFs with clear text content
|
|
18
|
+
# - Cost: Free
|
|
19
|
+
# - Use when: Document has clean, extractable text
|
|
20
|
+
#
|
|
21
|
+
# - **native**: Use model's native file processing capabilities
|
|
22
|
+
# - Cost: Charged as input tokens
|
|
23
|
+
# - Use when: Model supports native file input
|
|
24
|
+
#
|
|
25
|
+
# If no engine is specified, OpenRouter defaults to the model's native
|
|
26
|
+
# file processing if available, otherwise uses mistral-ocr.
|
|
27
|
+
#
|
|
28
|
+
# @example Text extraction (free)
|
|
19
29
|
# pdf_config = PdfConfig.new(engine: 'pdf-text')
|
|
30
|
+
#
|
|
31
|
+
# @example OCR for scanned documents
|
|
32
|
+
# pdf_config = PdfConfig.new(engine: 'mistral-ocr')
|
|
33
|
+
#
|
|
34
|
+
# @example Use model's native processing
|
|
35
|
+
# pdf_config = PdfConfig.new(engine: 'native')
|
|
36
|
+
#
|
|
37
|
+
# @see https://openrouter.ai/docs/plugins#file-parser OpenRouter File Parser Plugin
|
|
38
|
+
# @see Plugin
|
|
20
39
|
class PdfConfig < Common::BaseModel
|
|
40
|
+
# @!attribute engine
|
|
41
|
+
# @return [String, nil] PDF processing engine
|
|
42
|
+
# Options: 'mistral-ocr', 'pdf-text', 'native'
|
|
21
43
|
attribute :engine, :string
|
|
22
44
|
|
|
23
45
|
validates :engine, inclusion: { in: %w[mistral-ocr pdf-text native] }, allow_nil: true
|
|
@@ -4,8 +4,25 @@ module ActiveAgent
|
|
|
4
4
|
module Providers
|
|
5
5
|
module OpenRouter
|
|
6
6
|
module Requests
|
|
7
|
+
# Prediction configuration for prefilling responses
|
|
8
|
+
#
|
|
9
|
+
# Allows prefilling the start of the model's response. When provided,
|
|
10
|
+
# the model continues from this predicted content.
|
|
11
|
+
#
|
|
12
|
+
# @example Content prediction
|
|
13
|
+
# prediction = Prediction.new(
|
|
14
|
+
# type: 'content',
|
|
15
|
+
# content: 'Once upon a time'
|
|
16
|
+
# )
|
|
17
|
+
#
|
|
18
|
+
# @see https://platform.openai.com/docs/api-reference/chat/create#chat-create-prediction
|
|
7
19
|
class Prediction < Common::BaseModel
|
|
20
|
+
# @!attribute type
|
|
21
|
+
# @return [String] prediction type (currently only 'content' is supported)
|
|
8
22
|
attribute :type, :string
|
|
23
|
+
|
|
24
|
+
# @!attribute content
|
|
25
|
+
# @return [String] predicted content to prefill the response
|
|
9
26
|
attribute :content, :string
|
|
10
27
|
|
|
11
28
|
validates :type, inclusion: { in: %w[content] }, allow_nil: true
|
|
@@ -5,14 +5,48 @@ module ActiveAgent
|
|
|
5
5
|
module OpenRouter
|
|
6
6
|
module Requests
|
|
7
7
|
# Maximum price configuration for provider routing
|
|
8
|
-
#
|
|
9
|
-
#
|
|
8
|
+
#
|
|
9
|
+
# Specifies maximum acceptable prices (in USD per million tokens or per
|
|
10
|
+
# operation) for filtering providers. OpenRouter will only route to
|
|
11
|
+
# providers within these price constraints.
|
|
12
|
+
#
|
|
13
|
+
# @example Setting prompt and completion limits
|
|
14
|
+
# max_price = MaxPrice.new(
|
|
15
|
+
# prompt: 0.01, # $0.01 per million input tokens
|
|
16
|
+
# completion: 0.03 # $0.03 per million output tokens
|
|
17
|
+
# )
|
|
18
|
+
#
|
|
19
|
+
# @example Setting all constraints
|
|
20
|
+
# max_price = MaxPrice.new(
|
|
21
|
+
# prompt: 0.01,
|
|
22
|
+
# completion: 0.03,
|
|
23
|
+
# image: 0.001,
|
|
24
|
+
# audio: 0.002,
|
|
25
|
+
# request: 0.0001
|
|
26
|
+
# )
|
|
27
|
+
#
|
|
28
|
+
# @see https://openrouter.ai/docs/provider-routing OpenRouter Provider Routing
|
|
29
|
+
# @see ProviderPreferences
|
|
10
30
|
class MaxPrice < Common::BaseModel
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
attribute :
|
|
14
|
-
|
|
15
|
-
|
|
31
|
+
# @!attribute prompt
|
|
32
|
+
# @return [Float, nil] maximum price per million prompt tokens (input)
|
|
33
|
+
attribute :prompt, :float
|
|
34
|
+
|
|
35
|
+
# @!attribute completion
|
|
36
|
+
# @return [Float, nil] maximum price per million completion tokens (output)
|
|
37
|
+
attribute :completion, :float
|
|
38
|
+
|
|
39
|
+
# @!attribute image
|
|
40
|
+
# @return [Float, nil] maximum price per image operation
|
|
41
|
+
attribute :image, :float
|
|
42
|
+
|
|
43
|
+
# @!attribute audio
|
|
44
|
+
# @return [Float, nil] maximum price per audio operation
|
|
45
|
+
attribute :audio, :float
|
|
46
|
+
|
|
47
|
+
# @!attribute request
|
|
48
|
+
# @return [Float, nil] maximum price per request
|
|
49
|
+
attribute :request, :float
|
|
16
50
|
|
|
17
51
|
validates :prompt, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
|
|
18
52
|
validates :completion, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
|