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
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
module Providers
|
|
7
|
+
module Ollama
|
|
8
|
+
# Handles transformation and normalization of embedding request parameters
|
|
9
|
+
# for the Ollama Embeddings API
|
|
10
|
+
module Embedding
|
|
11
|
+
# Provides transformation methods for normalizing embedding parameters
|
|
12
|
+
# to Ollama API format with OpenAI gem compatibility
|
|
13
|
+
module Transforms
|
|
14
|
+
class << self
|
|
15
|
+
# Converts gem objects to hash representation
|
|
16
|
+
#
|
|
17
|
+
# @param obj [Object] gem object or primitive value
|
|
18
|
+
# @return [Hash, Object] hash if object supports JSON serialization
|
|
19
|
+
def gem_to_hash(obj)
|
|
20
|
+
if obj.respond_to?(:to_json)
|
|
21
|
+
JSON.parse(obj.to_json, symbolize_names: true)
|
|
22
|
+
else
|
|
23
|
+
obj
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Normalizes all embedding request parameters
|
|
28
|
+
#
|
|
29
|
+
# Ollama-specific parameters (options, keep_alive, truncate) are extracted
|
|
30
|
+
# and returned separately from OpenAI-compatible parameters.
|
|
31
|
+
#
|
|
32
|
+
# @param params [Hash] raw request parameters
|
|
33
|
+
# @return [Array<Hash, Hash>] tuple of [openai_params, ollama_params]
|
|
34
|
+
def normalize_params(params)
|
|
35
|
+
params = params.dup
|
|
36
|
+
|
|
37
|
+
# Extract Ollama-specific parameters
|
|
38
|
+
ollama_params = {}
|
|
39
|
+
ollama_params[:options] = params.delete(:options) if params.key?(:options)
|
|
40
|
+
ollama_params[:keep_alive] = params.delete(:keep_alive) if params.key?(:keep_alive)
|
|
41
|
+
ollama_params[:truncate] = params.delete(:truncate) if params.key?(:truncate)
|
|
42
|
+
|
|
43
|
+
# Extract options attributes that can be at top level
|
|
44
|
+
extract_option_attributes(params, ollama_params)
|
|
45
|
+
|
|
46
|
+
# Normalize input - Ollama only accepts strings, not token arrays
|
|
47
|
+
if params[:input]
|
|
48
|
+
params[:input] = normalize_input(params[:input])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
[ params, ollama_params ]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Normalizes input parameter to Ollama format
|
|
55
|
+
#
|
|
56
|
+
# Ollama only accepts strings or arrays of strings (no token arrays).
|
|
57
|
+
# Converts single string to array internally for consistency.
|
|
58
|
+
#
|
|
59
|
+
# @param input [String, Array<String>]
|
|
60
|
+
# @return [Array<String>] normalized input as array of strings
|
|
61
|
+
# @raise [ArgumentError] if input contains non-string values
|
|
62
|
+
def normalize_input(input)
|
|
63
|
+
case input
|
|
64
|
+
when String
|
|
65
|
+
[ input.presence ].compact
|
|
66
|
+
when Array
|
|
67
|
+
# Validate all elements are strings
|
|
68
|
+
input.each_with_index do |item, index|
|
|
69
|
+
unless item.is_a?(String)
|
|
70
|
+
raise ArgumentError, "Ollama embedding input must contain only strings, got #{item.class} at index #{index}"
|
|
71
|
+
end
|
|
72
|
+
if item.empty?
|
|
73
|
+
raise ArgumentError, "Ollama embedding input cannot contain empty strings at index #{index}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
input.compact
|
|
77
|
+
when nil
|
|
78
|
+
nil
|
|
79
|
+
else
|
|
80
|
+
raise ArgumentError, "Cannot normalize #{input.class} to Ollama input (expected String or Array)"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Serializes input for API submission
|
|
85
|
+
#
|
|
86
|
+
# Returns single string if array has only one element, otherwise array.
|
|
87
|
+
#
|
|
88
|
+
# @param input [Array<String>, nil]
|
|
89
|
+
# @return [String, Array<String>, nil]
|
|
90
|
+
def serialize_input(input)
|
|
91
|
+
return nil if input.nil?
|
|
92
|
+
|
|
93
|
+
# Return single string if array has only one element
|
|
94
|
+
if input.is_a?(Array) && input.length == 1
|
|
95
|
+
input.first
|
|
96
|
+
else
|
|
97
|
+
input
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Cleans up serialized request for API submission
|
|
102
|
+
#
|
|
103
|
+
# Merges OpenAI-compatible params with Ollama-specific params.
|
|
104
|
+
#
|
|
105
|
+
# @param openai_hash [Hash] serialized OpenAI-compatible request
|
|
106
|
+
# @param ollama_params [Hash] Ollama-specific parameters
|
|
107
|
+
# @param defaults [Hash] default values to remove
|
|
108
|
+
# @return [Hash] cleaned and merged request hash
|
|
109
|
+
def cleanup_serialized_request(openai_hash, ollama_params, defaults)
|
|
110
|
+
# Remove nil values
|
|
111
|
+
cleaned = openai_hash.compact
|
|
112
|
+
|
|
113
|
+
# Serialize input (convert single-element array to string)
|
|
114
|
+
if cleaned[:input]
|
|
115
|
+
cleaned[:input] = serialize_input(cleaned[:input])
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Merge Ollama-specific params, skip defaults
|
|
119
|
+
ollama_params.each do |key, value|
|
|
120
|
+
next if value.nil?
|
|
121
|
+
next if value.respond_to?(:empty?) && value.empty?
|
|
122
|
+
next if defaults.key?(key) && defaults[key] == value
|
|
123
|
+
|
|
124
|
+
# Serialize options object if present
|
|
125
|
+
cleaned[key] = if value.respond_to?(:serialize)
|
|
126
|
+
value.serialize
|
|
127
|
+
else
|
|
128
|
+
value
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
cleaned
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
# Extracts option attributes that can be specified at the top level
|
|
138
|
+
#
|
|
139
|
+
# @param params [Hash] request parameters
|
|
140
|
+
# @param ollama_params [Hash] ollama-specific parameters to populate
|
|
141
|
+
def extract_option_attributes(params, ollama_params)
|
|
142
|
+
option_keys = [
|
|
143
|
+
:mirostat, :mirostat_eta, :mirostat_tau, :num_ctx,
|
|
144
|
+
:repeat_last_n, :repeat_penalty, :temperature, :seed,
|
|
145
|
+
:num_predict, :top_k, :top_p, :min_p, :stop
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
option_keys.each do |key|
|
|
149
|
+
if params.key?(key)
|
|
150
|
+
ollama_params[:options] ||= {}
|
|
151
|
+
ollama_params[:options][key] = params.delete(key)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -56,7 +56,6 @@ module ActiveAgent
|
|
|
56
56
|
# @return [Hash] symbolized API response
|
|
57
57
|
# @raise [OpenAI::Errors::APIConnectionError] when Ollama server unreachable
|
|
58
58
|
def api_embed_execute(parameters)
|
|
59
|
-
instrument("embeddings_request.provider.active_agent")
|
|
60
59
|
client.embeddings.create(**parameters).as_json.deep_symbolize_keys
|
|
61
60
|
|
|
62
61
|
rescue ::OpenAI::Errors::APIConnectionError => exception
|
|
@@ -49,8 +49,9 @@ module ActiveAgent
|
|
|
49
49
|
name = api_function_call[:name]
|
|
50
50
|
kwargs = JSON.parse(api_function_call[:arguments], symbolize_names: true) if api_function_call[:arguments]
|
|
51
51
|
|
|
52
|
-
instrument("
|
|
53
|
-
|
|
52
|
+
instrument("tool_call.active_agent", tool_name: name) do
|
|
53
|
+
tools_function.call(name, **kwargs)
|
|
54
|
+
end
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
end
|
|
@@ -6,8 +6,13 @@ module ActiveAgent
|
|
|
6
6
|
module Providers
|
|
7
7
|
module OpenAI
|
|
8
8
|
module Chat
|
|
9
|
-
#
|
|
9
|
+
# ActiveModel type for casting and serializing chat requests
|
|
10
10
|
class RequestType < ActiveModel::Type::Value
|
|
11
|
+
# Casts value to Request object
|
|
12
|
+
#
|
|
13
|
+
# @param value [Request, Hash, nil]
|
|
14
|
+
# @return [Request, nil]
|
|
15
|
+
# @raise [ArgumentError] when value cannot be cast
|
|
11
16
|
def cast(value)
|
|
12
17
|
case value
|
|
13
18
|
when Request
|
|
@@ -21,6 +26,11 @@ module ActiveAgent
|
|
|
21
26
|
end
|
|
22
27
|
end
|
|
23
28
|
|
|
29
|
+
# Serializes Request to hash for API submission
|
|
30
|
+
#
|
|
31
|
+
# @param value [Request, Hash, nil]
|
|
32
|
+
# @return [Hash, nil]
|
|
33
|
+
# @raise [ArgumentError] when value cannot be serialized
|
|
24
34
|
def serialize(value)
|
|
25
35
|
case value
|
|
26
36
|
when Request
|
|
@@ -34,6 +44,8 @@ module ActiveAgent
|
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
|
|
47
|
+
# @param value [Object]
|
|
48
|
+
# @return [Request, nil]
|
|
37
49
|
def deserialize(value)
|
|
38
50
|
cast(value)
|
|
39
51
|
end
|
|
@@ -1,212 +1,158 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
|
|
3
|
+
require "delegate"
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "transforms"
|
|
5
6
|
|
|
6
7
|
module ActiveAgent
|
|
7
8
|
module Providers
|
|
8
9
|
module OpenAI
|
|
9
10
|
module Chat
|
|
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
|
-
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
attribute :temperature, :float, default: 1
|
|
89
|
-
|
|
90
|
-
# Tool choice
|
|
91
|
-
attribute :tool_choice, Requests::ToolChoiceType.new
|
|
92
|
-
|
|
93
|
-
# Tools array
|
|
94
|
-
attribute :tools # Array of tool objects
|
|
95
|
-
|
|
96
|
-
# Top logprobs
|
|
97
|
-
attribute :top_logprobs, :integer
|
|
98
|
-
|
|
99
|
-
# Top P sampling
|
|
100
|
-
attribute :top_p, :float, default: 1
|
|
101
|
-
|
|
102
|
-
# Deprecated: user (use safety_identifier or prompt_cache_key)
|
|
103
|
-
attribute :user, :string
|
|
104
|
-
|
|
105
|
-
# Verbosity (for reasoning models)
|
|
106
|
-
attribute :verbosity, :string
|
|
107
|
-
|
|
108
|
-
# Web search options
|
|
109
|
-
attribute :web_search_options, Requests::WebSearchOptionsType.new
|
|
110
|
-
|
|
111
|
-
# Validations
|
|
112
|
-
validates :model, :messages, presence: true
|
|
113
|
-
|
|
114
|
-
validates :frequency_penalty, numericality: { greater_than_or_equal_to: -2.0, less_than_or_equal_to: 2.0 }, allow_nil: true
|
|
115
|
-
validates :presence_penalty, numericality: { greater_than_or_equal_to: -2.0, less_than_or_equal_to: 2.0 }, allow_nil: true
|
|
116
|
-
validates :temperature, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 2 }, allow_nil: true
|
|
117
|
-
validates :top_p, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }, allow_nil: true
|
|
118
|
-
validates :top_logprobs, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 20 }, allow_nil: true
|
|
119
|
-
validates :n, numericality: { greater_than: 0 }, allow_nil: true
|
|
120
|
-
validates :max_completion_tokens, numericality: { greater_than: 0 }, allow_nil: true
|
|
121
|
-
validates :max_tokens, numericality: { greater_than: 0 }, allow_nil: true
|
|
122
|
-
|
|
123
|
-
validates :service_tier, inclusion: { in: %w[auto default flex priority] }, allow_nil: true
|
|
124
|
-
validates :reasoning_effort, inclusion: { in: %w[minimal low medium high] }, allow_nil: true
|
|
125
|
-
validates :verbosity, inclusion: { in: %w[low medium high] }, allow_nil: true
|
|
126
|
-
validates :modalities, inclusion: { in: %w[text audio] }, allow_nil: true
|
|
127
|
-
|
|
128
|
-
# Custom validations
|
|
129
|
-
validate :validate_metadata_format
|
|
130
|
-
validate :validate_logit_bias_format
|
|
131
|
-
validate :validate_stop_sequences
|
|
132
|
-
|
|
133
|
-
def serialize
|
|
134
|
-
super.tap do |hash|
|
|
135
|
-
# Can be an empty hash, to enable the feature
|
|
136
|
-
hash[:web_search_options] ||= {} if web_search_options
|
|
137
|
-
end
|
|
11
|
+
# Wraps OpenAI gem's CompletionCreateParams with normalization
|
|
12
|
+
#
|
|
13
|
+
# Delegates to OpenAI::Models::Chat::CompletionCreateParams while providing
|
|
14
|
+
# parameter normalization and shorthand format support via the Transforms module.
|
|
15
|
+
#
|
|
16
|
+
# All OpenAI Chat API fields are available via delegation:
|
|
17
|
+
# model, messages, temperature, max_tokens, max_completion_tokens, top_p,
|
|
18
|
+
# frequency_penalty, presence_penalty, tools, tool_choice, response_format,
|
|
19
|
+
# stream_options, audio, prediction, metadata, modalities, service_tier, store,
|
|
20
|
+
# parallel_tool_calls, reasoning_effort, verbosity, stop, seed, logit_bias,
|
|
21
|
+
# logprobs, top_logprobs, prompt_cache_key, safety_identifier, user,
|
|
22
|
+
# web_search_options, function_call, functions
|
|
23
|
+
#
|
|
24
|
+
# @example Basic usage
|
|
25
|
+
# request = Request.new(
|
|
26
|
+
# model: "gpt-4o",
|
|
27
|
+
# messages: [{role: "user", content: "Hello"}]
|
|
28
|
+
# )
|
|
29
|
+
#
|
|
30
|
+
# @example String message normalization
|
|
31
|
+
# Request.new(model: "gpt-4o", messages: "Hello")
|
|
32
|
+
# # Normalized to: [{role: "user", content: "Hello"}]
|
|
33
|
+
#
|
|
34
|
+
# @example Instructions support
|
|
35
|
+
# Request.new(
|
|
36
|
+
# model: "gpt-4o",
|
|
37
|
+
# messages: [{role: "user", content: "Hi"}],
|
|
38
|
+
# instructions: ["You are helpful", "Be concise"]
|
|
39
|
+
# )
|
|
40
|
+
# # instructions converted to developer messages and prepended
|
|
41
|
+
class Request < SimpleDelegator
|
|
42
|
+
# Default parameter values applied during initialization
|
|
43
|
+
DEFAULTS = {
|
|
44
|
+
frequency_penalty: 0,
|
|
45
|
+
logprobs: false,
|
|
46
|
+
modalities: [ "text" ],
|
|
47
|
+
n: 1,
|
|
48
|
+
parallel_tool_calls: true,
|
|
49
|
+
presence_penalty: 0,
|
|
50
|
+
service_tier: "auto",
|
|
51
|
+
store: false,
|
|
52
|
+
stream: false,
|
|
53
|
+
temperature: 1,
|
|
54
|
+
top_p: 1
|
|
55
|
+
}.freeze
|
|
56
|
+
|
|
57
|
+
# @return [Boolean, nil]
|
|
58
|
+
attr_reader :stream
|
|
59
|
+
|
|
60
|
+
# Creates a new chat completion request
|
|
61
|
+
#
|
|
62
|
+
# @param params [Hash] request parameters
|
|
63
|
+
# @option params [String] :model required model identifier
|
|
64
|
+
# @option params [Array, String, Hash] :messages required conversation messages
|
|
65
|
+
# @option params [Array<String>, String] :instructions system/developer prompts
|
|
66
|
+
# @option params [Hash, String, Symbol] :response_format
|
|
67
|
+
# @option params [Float] :temperature (1) sampling temperature 0-2
|
|
68
|
+
# @option params [Integer] :max_tokens maximum tokens to generate
|
|
69
|
+
# @option params [Array] :tools available tool definitions
|
|
70
|
+
# @raise [ArgumentError] when parameters are invalid
|
|
71
|
+
def initialize(**params)
|
|
72
|
+
# Step 1: Extract stream flag
|
|
73
|
+
@stream = params[:stream]
|
|
74
|
+
|
|
75
|
+
# Step 2: Apply defaults
|
|
76
|
+
params = apply_defaults(params)
|
|
77
|
+
|
|
78
|
+
# Step 3: Normalize all parameters (instructions, messages, response_format)
|
|
79
|
+
params = Chat::Transforms.normalize_params(params)
|
|
80
|
+
|
|
81
|
+
# Step 4: Create gem model - this validates all parameters!
|
|
82
|
+
gem_model = ::OpenAI::Models::Chat::CompletionCreateParams.new(**params)
|
|
83
|
+
|
|
84
|
+
# Step 5: Delegate all method calls to gem model
|
|
85
|
+
super(gem_model)
|
|
86
|
+
rescue ArgumentError => e
|
|
87
|
+
# Re-raise with more context
|
|
88
|
+
raise ArgumentError, "Invalid OpenAI Chat request parameters: #{e.message}"
|
|
138
89
|
end
|
|
139
90
|
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
|
|
91
|
+
# Serializes request for API call
|
|
92
|
+
#
|
|
93
|
+
# Uses gem's JSON serialization, removes default values for minimal
|
|
94
|
+
# request body, and simplifies messages where possible.
|
|
95
|
+
#
|
|
96
|
+
# @return [Hash] cleaned request hash
|
|
97
|
+
def serialize
|
|
98
|
+
# Use gem's JSON serialization (handles all nested objects)
|
|
99
|
+
hash = Chat::Transforms.gem_to_hash(__getobj__)
|
|
143
100
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
end
|
|
101
|
+
# Cleanup and simplify for API request
|
|
102
|
+
Chat::Transforms.cleanup_serialized_request(hash, DEFAULTS, __getobj__)
|
|
147
103
|
end
|
|
148
104
|
|
|
149
|
-
#
|
|
150
|
-
|
|
105
|
+
# @return [Array<Hash>, nil]
|
|
106
|
+
def messages
|
|
107
|
+
__getobj__.instance_variable_get(:@data)[:messages]
|
|
108
|
+
end
|
|
151
109
|
|
|
152
|
-
#
|
|
110
|
+
# Sets messages with normalization
|
|
111
|
+
#
|
|
112
|
+
# @param value [Array, String, Hash]
|
|
113
|
+
# @return [void]
|
|
153
114
|
def messages=(value)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
super((messages || []) | value)
|
|
157
|
-
else
|
|
158
|
-
super((messages || []) | [ value ])
|
|
159
|
-
end
|
|
115
|
+
normalized_value = Chat::Transforms.normalize_messages(value)
|
|
116
|
+
__getobj__.instance_variable_get(:@data)[:messages] = normalized_value
|
|
160
117
|
end
|
|
161
118
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
unless metadata.is_a?(Hash)
|
|
168
|
-
errors.add(:metadata, "must be a hash")
|
|
169
|
-
return
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
metadata.each do |key, value|
|
|
173
|
-
if key.to_s.length > 64
|
|
174
|
-
errors.add(:metadata, "keys must be 64 characters or less")
|
|
175
|
-
end
|
|
176
|
-
if value.to_s.length > 512
|
|
177
|
-
errors.add(:metadata, "values must be 512 characters or less")
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
if metadata.size > 16
|
|
182
|
-
errors.add(:metadata, "must have 16 key-value pairs or less")
|
|
183
|
-
end
|
|
119
|
+
# Alias for messages (common format compatibility)
|
|
120
|
+
#
|
|
121
|
+
# @return [Array<Hash>, nil]
|
|
122
|
+
def message
|
|
123
|
+
messages
|
|
184
124
|
end
|
|
185
125
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return
|
|
192
|
-
end
|
|
126
|
+
# @param value [Array, String, Hash]
|
|
127
|
+
# @return [void]
|
|
128
|
+
def message=(value)
|
|
129
|
+
self.messages = value
|
|
130
|
+
end
|
|
193
131
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
132
|
+
# Sets instructions as developer messages
|
|
133
|
+
#
|
|
134
|
+
# Prepends developer messages to the messages array for common format compatibility.
|
|
135
|
+
#
|
|
136
|
+
# @param values [Array<String>, String]
|
|
137
|
+
# @return [void]
|
|
138
|
+
def instructions=(*values)
|
|
139
|
+
instructions_messages = Chat::Transforms.normalize_instructions(values.flatten)
|
|
140
|
+
current_messages = messages || []
|
|
141
|
+
self.messages = instructions_messages + current_messages
|
|
199
142
|
end
|
|
200
143
|
|
|
201
|
-
|
|
202
|
-
return if stop.nil?
|
|
203
|
-
return if stop.is_a?(String)
|
|
144
|
+
private
|
|
204
145
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
146
|
+
# @api private
|
|
147
|
+
# @param params [Hash]
|
|
148
|
+
# @return [Hash]
|
|
149
|
+
def apply_defaults(params)
|
|
150
|
+
# Only apply defaults for keys that aren't present
|
|
151
|
+
DEFAULTS.each do |key, value|
|
|
152
|
+
params[key] = value unless params.key?(key)
|
|
209
153
|
end
|
|
154
|
+
|
|
155
|
+
params
|
|
210
156
|
end
|
|
211
157
|
end
|
|
212
158
|
end
|