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.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -1
  3. data/lib/active_agent/providers/_base_provider.rb +92 -82
  4. data/lib/active_agent/providers/anthropic/_types.rb +2 -2
  5. data/lib/active_agent/providers/anthropic/request.rb +135 -81
  6. data/lib/active_agent/providers/anthropic/transforms.rb +353 -0
  7. data/lib/active_agent/providers/anthropic_provider.rb +96 -53
  8. data/lib/active_agent/providers/common/messages/_types.rb +37 -1
  9. data/lib/active_agent/providers/common/responses/base.rb +118 -70
  10. data/lib/active_agent/providers/common/usage.rb +385 -0
  11. data/lib/active_agent/providers/concerns/instrumentation.rb +263 -0
  12. data/lib/active_agent/providers/log_subscriber.rb +64 -246
  13. data/lib/active_agent/providers/mock_provider.rb +23 -23
  14. data/lib/active_agent/providers/ollama/chat/request.rb +214 -35
  15. data/lib/active_agent/providers/ollama/chat/transforms.rb +135 -0
  16. data/lib/active_agent/providers/ollama/embedding/request.rb +160 -47
  17. data/lib/active_agent/providers/ollama/embedding/transforms.rb +160 -0
  18. data/lib/active_agent/providers/ollama_provider.rb +0 -1
  19. data/lib/active_agent/providers/open_ai/_base.rb +3 -2
  20. data/lib/active_agent/providers/open_ai/chat/_types.rb +13 -1
  21. data/lib/active_agent/providers/open_ai/chat/request.rb +132 -186
  22. data/lib/active_agent/providers/open_ai/chat/transforms.rb +364 -0
  23. data/lib/active_agent/providers/open_ai/chat_provider.rb +57 -36
  24. data/lib/active_agent/providers/open_ai/embedding/_types.rb +13 -2
  25. data/lib/active_agent/providers/open_ai/embedding/request.rb +38 -70
  26. data/lib/active_agent/providers/open_ai/embedding/transforms.rb +88 -0
  27. data/lib/active_agent/providers/open_ai/responses/_types.rb +1 -7
  28. data/lib/active_agent/providers/open_ai/responses/request.rb +100 -134
  29. data/lib/active_agent/providers/open_ai/responses/transforms.rb +228 -0
  30. data/lib/active_agent/providers/open_ai/responses_provider.rb +77 -30
  31. data/lib/active_agent/providers/open_ai_provider.rb +0 -3
  32. data/lib/active_agent/providers/open_router/_types.rb +27 -1
  33. data/lib/active_agent/providers/open_router/options.rb +49 -1
  34. data/lib/active_agent/providers/open_router/request.rb +232 -66
  35. data/lib/active_agent/providers/open_router/requests/_types.rb +0 -1
  36. data/lib/active_agent/providers/open_router/requests/messages/_types.rb +37 -40
  37. data/lib/active_agent/providers/open_router/requests/messages/content/file.rb +19 -3
  38. data/lib/active_agent/providers/open_router/requests/messages/content/files/details.rb +15 -4
  39. data/lib/active_agent/providers/open_router/requests/plugin.rb +19 -3
  40. data/lib/active_agent/providers/open_router/requests/plugins/pdf_config.rb +30 -8
  41. data/lib/active_agent/providers/open_router/requests/prediction.rb +17 -0
  42. data/lib/active_agent/providers/open_router/requests/provider_preferences/max_price.rb +41 -7
  43. data/lib/active_agent/providers/open_router/requests/provider_preferences.rb +60 -19
  44. data/lib/active_agent/providers/open_router/requests/response_format.rb +30 -2
  45. data/lib/active_agent/providers/open_router/transforms.rb +134 -0
  46. data/lib/active_agent/providers/open_router_provider.rb +9 -0
  47. data/lib/active_agent/version.rb +1 -1
  48. metadata +15 -159
  49. data/lib/active_agent/generation_provider/open_router/types.rb +0 -505
  50. data/lib/active_agent/generation_provider/xai_provider.rb +0 -144
  51. data/lib/active_agent/providers/anthropic/requests/_types.rb +0 -190
  52. data/lib/active_agent/providers/anthropic/requests/container_params.rb +0 -19
  53. data/lib/active_agent/providers/anthropic/requests/content/base.rb +0 -21
  54. data/lib/active_agent/providers/anthropic/requests/content/sources/base.rb +0 -22
  55. data/lib/active_agent/providers/anthropic/requests/context_management_config.rb +0 -18
  56. data/lib/active_agent/providers/anthropic/requests/messages/_types.rb +0 -189
  57. data/lib/active_agent/providers/anthropic/requests/messages/assistant.rb +0 -23
  58. data/lib/active_agent/providers/anthropic/requests/messages/base.rb +0 -63
  59. data/lib/active_agent/providers/anthropic/requests/messages/content/_types.rb +0 -143
  60. data/lib/active_agent/providers/anthropic/requests/messages/content/base.rb +0 -21
  61. data/lib/active_agent/providers/anthropic/requests/messages/content/document.rb +0 -26
  62. data/lib/active_agent/providers/anthropic/requests/messages/content/image.rb +0 -23
  63. data/lib/active_agent/providers/anthropic/requests/messages/content/redacted_thinking.rb +0 -21
  64. data/lib/active_agent/providers/anthropic/requests/messages/content/search_result.rb +0 -27
  65. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/_types.rb +0 -171
  66. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/base.rb +0 -22
  67. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_base64.rb +0 -25
  68. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_file.rb +0 -23
  69. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_text.rb +0 -25
  70. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/document_url.rb +0 -23
  71. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_base64.rb +0 -27
  72. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_file.rb +0 -23
  73. data/lib/active_agent/providers/anthropic/requests/messages/content/sources/image_url.rb +0 -23
  74. data/lib/active_agent/providers/anthropic/requests/messages/content/text.rb +0 -22
  75. data/lib/active_agent/providers/anthropic/requests/messages/content/thinking.rb +0 -23
  76. data/lib/active_agent/providers/anthropic/requests/messages/content/tool_result.rb +0 -24
  77. data/lib/active_agent/providers/anthropic/requests/messages/content/tool_use.rb +0 -28
  78. data/lib/active_agent/providers/anthropic/requests/messages/user.rb +0 -21
  79. data/lib/active_agent/providers/anthropic/requests/metadata.rb +0 -18
  80. data/lib/active_agent/providers/anthropic/requests/response_format.rb +0 -22
  81. data/lib/active_agent/providers/anthropic/requests/thinking_config/_types.rb +0 -60
  82. data/lib/active_agent/providers/anthropic/requests/thinking_config/base.rb +0 -20
  83. data/lib/active_agent/providers/anthropic/requests/thinking_config/disabled.rb +0 -16
  84. data/lib/active_agent/providers/anthropic/requests/thinking_config/enabled.rb +0 -20
  85. data/lib/active_agent/providers/anthropic/requests/tool_choice/_types.rb +0 -78
  86. data/lib/active_agent/providers/anthropic/requests/tool_choice/any.rb +0 -17
  87. data/lib/active_agent/providers/anthropic/requests/tool_choice/auto.rb +0 -17
  88. data/lib/active_agent/providers/anthropic/requests/tool_choice/base.rb +0 -20
  89. data/lib/active_agent/providers/anthropic/requests/tool_choice/none.rb +0 -16
  90. data/lib/active_agent/providers/anthropic/requests/tool_choice/tool.rb +0 -20
  91. data/lib/active_agent/providers/ollama/chat/requests/_types.rb +0 -3
  92. data/lib/active_agent/providers/ollama/chat/requests/messages/_types.rb +0 -116
  93. data/lib/active_agent/providers/ollama/chat/requests/messages/assistant.rb +0 -19
  94. data/lib/active_agent/providers/ollama/chat/requests/messages/user.rb +0 -19
  95. data/lib/active_agent/providers/ollama/embedding/requests/_types.rb +0 -83
  96. data/lib/active_agent/providers/ollama/embedding/requests/options.rb +0 -104
  97. data/lib/active_agent/providers/open_ai/chat/requests/_types.rb +0 -229
  98. data/lib/active_agent/providers/open_ai/chat/requests/audio.rb +0 -24
  99. data/lib/active_agent/providers/open_ai/chat/requests/messages/_types.rb +0 -123
  100. data/lib/active_agent/providers/open_ai/chat/requests/messages/assistant.rb +0 -42
  101. data/lib/active_agent/providers/open_ai/chat/requests/messages/base.rb +0 -78
  102. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/_types.rb +0 -133
  103. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/audio.rb +0 -35
  104. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/base.rb +0 -24
  105. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/file.rb +0 -26
  106. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/_types.rb +0 -60
  107. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/files/details.rb +0 -41
  108. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/image.rb +0 -37
  109. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/refusal.rb +0 -25
  110. data/lib/active_agent/providers/open_ai/chat/requests/messages/content/text.rb +0 -25
  111. data/lib/active_agent/providers/open_ai/chat/requests/messages/developer.rb +0 -25
  112. data/lib/active_agent/providers/open_ai/chat/requests/messages/function.rb +0 -25
  113. data/lib/active_agent/providers/open_ai/chat/requests/messages/system.rb +0 -25
  114. data/lib/active_agent/providers/open_ai/chat/requests/messages/tool.rb +0 -26
  115. data/lib/active_agent/providers/open_ai/chat/requests/messages/user.rb +0 -32
  116. data/lib/active_agent/providers/open_ai/chat/requests/prediction.rb +0 -46
  117. data/lib/active_agent/providers/open_ai/chat/requests/response_format.rb +0 -53
  118. data/lib/active_agent/providers/open_ai/chat/requests/stream_options.rb +0 -24
  119. data/lib/active_agent/providers/open_ai/chat/requests/tool_choice.rb +0 -26
  120. data/lib/active_agent/providers/open_ai/chat/requests/tools/_types.rb +0 -5
  121. data/lib/active_agent/providers/open_ai/chat/requests/tools/base.rb +0 -22
  122. data/lib/active_agent/providers/open_ai/chat/requests/tools/custom_tool.rb +0 -41
  123. data/lib/active_agent/providers/open_ai/chat/requests/tools/function_tool.rb +0 -51
  124. data/lib/active_agent/providers/open_ai/chat/requests/web_search_options.rb +0 -45
  125. data/lib/active_agent/providers/open_ai/embedding/requests/_types.rb +0 -49
  126. data/lib/active_agent/providers/open_ai/responses/requests/_types.rb +0 -231
  127. data/lib/active_agent/providers/open_ai/responses/requests/conversation.rb +0 -23
  128. data/lib/active_agent/providers/open_ai/responses/requests/inputs/_types.rb +0 -264
  129. data/lib/active_agent/providers/open_ai/responses/requests/inputs/assistant_message.rb +0 -22
  130. data/lib/active_agent/providers/open_ai/responses/requests/inputs/base.rb +0 -89
  131. data/lib/active_agent/providers/open_ai/responses/requests/inputs/code_interpreter_tool_call.rb +0 -30
  132. data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call.rb +0 -28
  133. data/lib/active_agent/providers/open_ai/responses/requests/inputs/computer_tool_call_output.rb +0 -33
  134. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/_types.rb +0 -207
  135. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/base.rb +0 -22
  136. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_audio.rb +0 -26
  137. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_file.rb +0 -28
  138. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_image.rb +0 -28
  139. data/lib/active_agent/providers/open_ai/responses/requests/inputs/content/input_text.rb +0 -25
  140. data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call.rb +0 -28
  141. data/lib/active_agent/providers/open_ai/responses/requests/inputs/custom_tool_call_output.rb +0 -27
  142. data/lib/active_agent/providers/open_ai/responses/requests/inputs/developer_message.rb +0 -20
  143. data/lib/active_agent/providers/open_ai/responses/requests/inputs/file_search_tool_call.rb +0 -25
  144. data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_call_output.rb +0 -32
  145. data/lib/active_agent/providers/open_ai/responses/requests/inputs/function_tool_call.rb +0 -28
  146. data/lib/active_agent/providers/open_ai/responses/requests/inputs/image_gen_tool_call.rb +0 -27
  147. data/lib/active_agent/providers/open_ai/responses/requests/inputs/input_message.rb +0 -31
  148. data/lib/active_agent/providers/open_ai/responses/requests/inputs/item_reference.rb +0 -23
  149. data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call.rb +0 -26
  150. data/lib/active_agent/providers/open_ai/responses/requests/inputs/local_shell_tool_call_output.rb +0 -33
  151. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_request.rb +0 -30
  152. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_approval_response.rb +0 -28
  153. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_list_tools.rb +0 -29
  154. data/lib/active_agent/providers/open_ai/responses/requests/inputs/mcp_tool_call.rb +0 -35
  155. data/lib/active_agent/providers/open_ai/responses/requests/inputs/output_message.rb +0 -35
  156. data/lib/active_agent/providers/open_ai/responses/requests/inputs/reasoning.rb +0 -33
  157. data/lib/active_agent/providers/open_ai/responses/requests/inputs/system_message.rb +0 -20
  158. data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_call_base.rb +0 -27
  159. data/lib/active_agent/providers/open_ai/responses/requests/inputs/tool_message.rb +0 -23
  160. data/lib/active_agent/providers/open_ai/responses/requests/inputs/user_message.rb +0 -20
  161. data/lib/active_agent/providers/open_ai/responses/requests/inputs/web_search_tool_call.rb +0 -24
  162. data/lib/active_agent/providers/open_ai/responses/requests/prompt_reference.rb +0 -23
  163. data/lib/active_agent/providers/open_ai/responses/requests/reasoning.rb +0 -23
  164. data/lib/active_agent/providers/open_ai/responses/requests/stream_options.rb +0 -20
  165. data/lib/active_agent/providers/open_ai/responses/requests/text/_types.rb +0 -89
  166. data/lib/active_agent/providers/open_ai/responses/requests/text/base.rb +0 -22
  167. data/lib/active_agent/providers/open_ai/responses/requests/text/json_object.rb +0 -20
  168. data/lib/active_agent/providers/open_ai/responses/requests/text/json_schema.rb +0 -48
  169. data/lib/active_agent/providers/open_ai/responses/requests/text/plain.rb +0 -20
  170. data/lib/active_agent/providers/open_ai/responses/requests/text.rb +0 -41
  171. data/lib/active_agent/providers/open_ai/responses/requests/tool_choice.rb +0 -26
  172. data/lib/active_agent/providers/open_ai/responses/requests/tools/_types.rb +0 -112
  173. data/lib/active_agent/providers/open_ai/responses/requests/tools/base.rb +0 -25
  174. data/lib/active_agent/providers/open_ai/responses/requests/tools/code_interpreter_tool.rb +0 -23
  175. data/lib/active_agent/providers/open_ai/responses/requests/tools/computer_tool.rb +0 -27
  176. data/lib/active_agent/providers/open_ai/responses/requests/tools/custom_tool.rb +0 -28
  177. data/lib/active_agent/providers/open_ai/responses/requests/tools/file_search_tool.rb +0 -27
  178. data/lib/active_agent/providers/open_ai/responses/requests/tools/function_tool.rb +0 -29
  179. data/lib/active_agent/providers/open_ai/responses/requests/tools/image_generation_tool.rb +0 -37
  180. data/lib/active_agent/providers/open_ai/responses/requests/tools/local_shell_tool.rb +0 -21
  181. data/lib/active_agent/providers/open_ai/responses/requests/tools/mcp_tool.rb +0 -41
  182. data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_preview_tool.rb +0 -24
  183. data/lib/active_agent/providers/open_ai/responses/requests/tools/web_search_tool.rb +0 -25
  184. data/lib/active_agent/providers/open_ai/schema.yml +0 -65937
  185. data/lib/active_agent/providers/open_router/requests/message.rb +0 -1
  186. data/lib/active_agent/providers/open_router/requests/messages/assistant.rb +0 -20
  187. data/lib/active_agent/providers/open_router/requests/messages/user.rb +0 -30
@@ -1,82 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_agent/providers/common/model"
4
- require_relative "_types"
3
+ require "json"
4
+ require_relative "transforms"
5
5
 
6
6
  module ActiveAgent
7
7
  module Providers
8
8
  module OpenAI
9
9
  module Embedding
10
- class Request < Common::BaseModel
11
- # Input text to embed (required)
12
- # Can be a string or array of strings or array of token arrays
13
- # - Must not exceed max input tokens for the model (8192 for all embedding models)
14
- # - Cannot be an empty string
15
- # - Arrays must be 2048 dimensions or less
16
- # - Maximum of 300,000 tokens summed across all inputs in a single request
17
- attribute :input, Requests::InputType.new
18
-
19
- # Model ID (required)
20
- attribute :model, :string
21
-
22
- # Number of dimensions for output embeddings (optional)
23
- # Only supported in text-embedding-3 and later models
24
- attribute :dimensions, :integer
25
-
26
- # Format for returned embeddings (optional)
27
- # Can be "float" or "base64"
28
- attribute :encoding_format, :string, default: "float"
29
-
30
- # Unique identifier for end-user (optional, deprecated)
31
- # Can help OpenAI monitor and detect abuse
32
- attribute :user, :string
33
-
34
- # Validations
35
- validates :input, :model, presence: true
36
- validates :encoding_format, inclusion: { in: %w[float base64] }, allow_nil: true
37
- validates :dimensions, numericality: { greater_than: 0 }, allow_nil: true
38
-
39
- # Custom validations
40
- validate :validate_input_format
41
- validate :validate_input_not_empty
42
-
43
- private
44
-
45
- def validate_input_format
46
- return if input.nil?
47
-
48
- unless input.is_a?(Array)
49
- errors.add(:input, "must be stored as an array internally")
50
- return
51
- end
52
-
53
- # Validate array contents
54
- input.each_with_index do |item, index|
55
- case item
56
- when String
57
- if item.empty?
58
- errors.add(:input, "cannot contain empty strings at index #{index}")
59
- end
60
- when Array
61
- # Token array validation
62
- if item.length > 2048
63
- errors.add(:input, "token arrays must be 2048 dimensions or less at index #{index}")
64
- end
65
- if item.empty?
66
- errors.add(:input, "cannot contain empty token arrays at index #{index}")
67
- end
68
- else
69
- errors.add(:input, "array elements must be strings or token arrays at index #{index}")
70
- end
71
- end
10
+ # Wraps OpenAI gem's EmbeddingCreateParams with normalization
11
+ #
12
+ # Delegates to OpenAI::Models::EmbeddingCreateParams while providing
13
+ # parameter normalization via the Transforms module
14
+ class Request < SimpleDelegator
15
+ # Default parameter values applied during initialization
16
+ DEFAULTS = {}.freeze
17
+
18
+ # Creates a new embedding request
19
+ #
20
+ # @param params [Hash] embedding parameters
21
+ # @option params [String, Array<String>, Array<Integer>, Array<Array<Integer>>] :input
22
+ # text or token array(s) to embed
23
+ # @option params [String] :model embedding model identifier
24
+ # @option params [Integer, nil] :dimensions number of dimensions for output (text-embedding-3 only)
25
+ # @option params [String, nil] :encoding_format "float" or "base64"
26
+ # @option params [String, nil] :user unique user identifier
27
+ # @raise [ArgumentError] when parameters are invalid
28
+ def initialize(**params)
29
+ # Step 1: Normalize parameters
30
+ params = Transforms.normalize_params(params)
31
+
32
+ # Step 2: Create gem model - this validates all parameters!
33
+ gem_model = ::OpenAI::Models::EmbeddingCreateParams.new(**params)
34
+
35
+ # Step 3: Delegate all method calls to gem model
36
+ super(gem_model)
37
+ rescue ArgumentError => e
38
+ # Re-raise with more context
39
+ raise ArgumentError, "Invalid OpenAI Embedding request parameters: #{e.message}"
72
40
  end
73
41
 
74
- def validate_input_not_empty
75
- return if input.nil?
76
-
77
- if input.is_a?(Array) && input.empty?
78
- errors.add(:input, "cannot be an empty array")
79
- end
42
+ # Serializes request for API submission
43
+ #
44
+ # @return [Hash] cleaned request hash without nil values
45
+ def serialize
46
+ serialized = Transforms.gem_to_hash(__getobj__)
47
+ Transforms.cleanup_serialized_request(serialized, DEFAULTS, __getobj__)
80
48
  end
81
49
  end
82
50
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAgent
4
+ module Providers
5
+ module OpenAI
6
+ # Handles transformation and normalization of embedding request parameters
7
+ # for the OpenAI Embeddings API
8
+ module Embedding
9
+ # Provides transformation methods for normalizing embedding parameters
10
+ # to OpenAI gem's native format
11
+ module Transforms
12
+ # Converts OpenAI gem objects to hash representation
13
+ #
14
+ # @param obj [Object] gem object or primitive value
15
+ # @return [Hash, Object] hash if object supports JSON serialization, otherwise original object
16
+ def self.gem_to_hash(obj)
17
+ if obj.respond_to?(:to_json)
18
+ JSON.parse(obj.to_json)
19
+ else
20
+ obj
21
+ end
22
+ end
23
+
24
+ # Normalizes all embedding request parameters
25
+ #
26
+ # @param params [Hash] raw request parameters
27
+ # @return [Hash] normalized parameters
28
+ def self.normalize_params(params)
29
+ normalized = params.dup
30
+
31
+ if normalized[:input]
32
+ normalized[:input] = normalize_input(normalized[:input])
33
+ end
34
+
35
+ normalized
36
+ end
37
+
38
+ # Normalizes input parameter to supported format
39
+ #
40
+ # Handles multiple input formats:
41
+ # - `"text"` - single string for one embedding
42
+ # - `["text1", "text2"]` - array of strings for multiple embeddings
43
+ # - `[1, 2, 3]` - token array for single embedding
44
+ # - `[[1, 2], [3, 4]]` - array of token arrays for multiple embeddings
45
+ #
46
+ # @param input [String, Array<String>, Array<Integer>, Array<Array<Integer>>]
47
+ # @return [String, Array] normalized input in gem-compatible format
48
+ def self.normalize_input(input)
49
+ case input
50
+ when String
51
+ input
52
+ when Array
53
+ if input.empty?
54
+ input
55
+ elsif input.first.is_a?(Integer)
56
+ input
57
+ elsif input.first.is_a?(Array)
58
+ input
59
+ else
60
+ input
61
+ end
62
+ else
63
+ input
64
+ end
65
+ end
66
+
67
+ # Removes nil values from serialized request
68
+ #
69
+ # @param serialized [Hash] serialized request
70
+ # @param defaults [Hash] default values to remove
71
+ # @param gem_object [Object] original gem object (unused but for consistency)
72
+ # @return [Hash] cleaned request hash
73
+ def self.cleanup_serialized_request(serialized, defaults = {}, gem_object = nil)
74
+ # Remove nil values
75
+ cleaned = serialized.compact
76
+
77
+ # Remove default values
78
+ defaults.each do |key, value|
79
+ cleaned.delete(key) if cleaned[key] == value
80
+ end
81
+
82
+ cleaned
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -24,13 +24,7 @@ module ActiveAgent
24
24
  def serialize(value)
25
25
  case value
26
26
  when Request
27
- hash = value.serialize
28
-
29
- if hash[:input] in [ { role: "user", content: String } ]
30
- hash[:input] = hash[:input][0][:content]
31
- end
32
-
33
- hash
27
+ value.serialize
34
28
  when Hash
35
29
  value
36
30
  when nil
@@ -1,160 +1,126 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_agent/providers/common/model"
4
- require_relative "requests/_types"
3
+ require_relative "transforms"
5
4
 
6
5
  module ActiveAgent
7
6
  module Providers
8
7
  module OpenAI
9
8
  module Responses
10
- class Request < Common::BaseModel
11
- # Background execution
12
- attribute :background, :boolean, default: false
13
-
14
- # Conversation
15
- attribute :conversation, Requests::ConversationType.new
16
-
17
- # Include additional output data
18
- attribute :include, default: -> { [] } # Array of strings
19
-
20
- # Input items (text, image, or file inputs)
21
- attribute :input, Requests::Inputs::MessagesType.new
22
-
23
- # Instructions (system/developer message)
24
- attribute :instructions, :string
25
-
26
- # Token limits
27
- attribute :max_output_tokens, :integer
28
- attribute :max_tool_calls, :integer
29
-
30
- # Metadata
31
- attribute :metadata # Hash of key-value pairs
32
-
33
- # Model ID
34
- attribute :model, :string
35
-
36
- # Parallel tool calls
37
- attribute :parallel_tool_calls, :boolean, default: true
38
-
39
- # Previous response ID for multi-turn conversations
40
- attribute :previous_response_id, :string
41
-
42
- # Prompt template reference
43
- attribute :prompt, Requests::PromptReferenceType.new
44
-
45
- # Cache key for optimization
46
- attribute :prompt_cache_key, :string
47
-
48
- # Reasoning configuration (for o-series and gpt-5 models)
49
- attribute :reasoning, Requests::ReasoningType.new
50
-
51
- # Safety identifier for usage policy detection
52
- attribute :safety_identifier, :string
53
-
54
- # Service tier
55
- attribute :service_tier, :string, default: "auto"
56
-
57
- # Storage
58
- attribute :store, :boolean, default: true
59
-
60
- # Streaming
61
- attribute :stream, :boolean, default: false
62
- attribute :stream_options, Requests::StreamOptionsType.new
63
-
64
- # Temperature sampling
65
- attribute :temperature, :float, default: 1
66
-
67
- # Text response configuration
68
- attribute :text, Requests::TextType.new
69
-
70
- # Tool choice
71
- attribute :tool_choice, Requests::ToolChoiceType.new
72
-
73
- # Tools array
74
- attribute :tools, Requests::Tools::ToolsType.new
75
-
76
- # Top logprobs
77
- attribute :top_logprobs, :integer
78
-
79
- # Top P sampling
80
- attribute :top_p, :float, default: 1
9
+ # Wraps OpenAI gem's ResponseCreateParams with field mapping and normalization
10
+ #
11
+ # Delegates to OpenAI::Models::Responses::ResponseCreateParams while providing
12
+ # compatibility layer for common format fields and content normalization:
13
+ # - `messages` → `input`
14
+ # - `response_format` → `text` (via ResponseTextConfig)
15
+ # - Instructions array joined to string
16
+ class Request < SimpleDelegator
17
+ # Default parameter values applied during initialization
18
+ DEFAULTS = {
19
+ service_tier: "auto",
20
+ store: true,
21
+ temperature: 1.0,
22
+ top_p: 1.0,
23
+ truncation: "disabled",
24
+ parallel_tool_calls: true,
25
+ background: false,
26
+ include: []
27
+ }.freeze
28
+
29
+ # @return [Boolean, nil]
30
+ attr_reader :stream
31
+
32
+ # @return [Hash, nil]
33
+ attr_reader :response_format
34
+
35
+ # Creates a new response creation request
36
+ #
37
+ # Maps common format fields to Responses API format:
38
+ # - `messages` `input`
39
+ # - `response_format` → `text` parameter
40
+ # - Instructions array → joined string
41
+ #
42
+ # @param params [Hash] request parameters
43
+ # @option params [String] :model required model identifier
44
+ # @option params [Array, String, Hash] :input messages or content
45
+ # @option params [Array, String, Hash] :messages alternative to :input (mapped automatically)
46
+ # @option params [Hash, String, Symbol] :response_format
47
+ # @option params [Array<String>, String] :instructions
48
+ # @option params [Integer] :max_output_tokens
49
+ # @raise [ArgumentError] when parameters are invalid
50
+ def initialize(**params)
51
+ # Step 1: Extract custom fields
52
+ @stream = params[:stream]
53
+ @response_format = params.delete(:response_format)
54
+
55
+ # Step 2: Map common format 'messages' to OpenAI Responses 'input'
56
+ if params.key?(:messages)
57
+ params[:input] = params.delete(:messages)
58
+ end
81
59
 
82
- # Truncation strategy
83
- attribute :truncation, :string, default: "disabled"
60
+ # Step 3: Join instructions array into string (like Chat API)
61
+ if params[:instructions].is_a?(Array)
62
+ params[:instructions] = params[:instructions].join("\n")
63
+ end
84
64
 
85
- # User identifier (deprecated, use safety_identifier or prompt_cache_key)
86
- attribute :user, :string
65
+ # Step 4: Map response_format to text parameter for Responses API
66
+ if @response_format
67
+ params[:text] = Responses::Transforms.normalize_response_format(@response_format)
68
+ end
87
69
 
88
- # Validations
89
- validates :max_output_tokens, numericality: { greater_than: 0 }, allow_nil: true
90
- validates :max_tool_calls, numericality: { greater_than: 0 }, allow_nil: true
91
- validates :temperature, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 2 }, allow_nil: true
92
- validates :top_p, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }, allow_nil: true
93
- validates :top_logprobs, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 20 }, allow_nil: true
94
- validates :service_tier, inclusion: { in: %w[auto default flex priority] }, allow_nil: true
95
- validates :truncation, inclusion: { in: %w[auto disabled] }, allow_nil: true
70
+ # Step 5: Apply defaults
71
+ params = apply_defaults(params)
96
72
 
97
- validate :validate_conversation_exclusivity
98
- validate :validate_metadata_format
99
- validate :validate_include_values
73
+ # Step 6: Normalize input content for gem compatibility
74
+ params[:input] = Responses::Transforms.normalize_input(params[:input]) if params[:input]
100
75
 
101
- # Common Format Mapping
102
- alias_attribute :messages, :input
103
- alias_attribute :message, :input
104
- alias_attribute :response_format, :text
76
+ # Step 7: Create gem model - delegates to OpenAI gem
77
+ gem_model = ::OpenAI::Models::Responses::ResponseCreateParams.new(**params)
105
78
 
106
- # Common Format Compatability
107
- def instructions=(value)
108
- super(value.is_a?(Array) ? value.join("\n") : value)
79
+ # Step 8: Delegate all method calls to gem model
80
+ super(gem_model)
81
+ rescue ArgumentError => e
82
+ # Re-raise with more context
83
+ raise ArgumentError, "Invalid OpenAI Responses request parameters: #{e.message}"
109
84
  end
110
85
 
111
- private
86
+ # Serializes request for API call
87
+ #
88
+ # Uses gem's JSON serialization and delegates cleanup to Transforms module.
89
+ #
90
+ # @return [Hash] cleaned request hash
91
+ def serialize
92
+ hash = Responses::Transforms.gem_to_hash(__getobj__)
93
+ Responses::Transforms.cleanup_serialized_request(hash, DEFAULTS, __getobj__)
94
+ end
112
95
 
113
- def validate_conversation_exclusivity
114
- if conversation.present? && previous_response_id.present?
115
- errors.add(:base, "Cannot use both conversation and previous_response_id")
116
- end
96
+ # @return [Array, String, Hash, nil]
97
+ def messages
98
+ __getobj__.instance_variable_get(:@data)[:input]
117
99
  end
118
100
 
119
- def validate_metadata_format
120
- return if metadata.nil?
101
+ # Sets input messages with normalization
102
+ #
103
+ # @param value [Array, String, Hash]
104
+ # @return [void]
105
+ def messages=(value)
106
+ normalized_value = Responses::Transforms.normalize_input(value)
107
+ __getobj__.instance_variable_get(:@data)[:input] = normalized_value
108
+ end
121
109
 
122
- unless metadata.is_a?(Hash)
123
- errors.add(:metadata, "must be a hash")
124
- return
125
- end
110
+ alias_method :message, :messages
111
+ alias_method :message=, :messages=
126
112
 
127
- metadata.each do |key, value|
128
- if key.to_s.length > 64
129
- errors.add(:metadata, "keys must be 64 characters or less")
130
- end
131
- if value.to_s.length > 512
132
- errors.add(:metadata, "values must be 512 characters or less")
133
- end
134
- end
113
+ private
135
114
 
136
- if metadata.size > 16
137
- errors.add(:metadata, "must have 16 key-value pairs or less")
115
+ # @api private
116
+ # @param params [Hash]
117
+ # @return [Hash]
118
+ def apply_defaults(params)
119
+ DEFAULTS.each do |key, value|
120
+ params[key] = value unless params.key?(key)
138
121
  end
139
- end
140
122
 
141
- def validate_include_values
142
- return if include.nil? || include.empty?
143
-
144
- valid_include_values = [
145
- "web_search_call.action.sources",
146
- "code_interpreter_call.outputs",
147
- "computer_call_output.output.image_url",
148
- "file_search_call.results",
149
- "message.input_image.image_url",
150
- "message.output_text.logprobs",
151
- "reasoning.encrypted_content"
152
- ]
153
-
154
- invalid_values = include - valid_include_values
155
- if invalid_values.any?
156
- errors.add(:include, "contains invalid values: #{invalid_values.join(', ')}")
157
- end
123
+ params
158
124
  end
159
125
  end
160
126
  end