geminize 1.0.0 → 1.2.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/mcp.json +3 -0
  3. data/.cursor/rules/isolation_rules/Core/command-execution.mdc +235 -0
  4. data/.cursor/rules/isolation_rules/Core/complexity-decision-tree.mdc +187 -0
  5. data/.cursor/rules/isolation_rules/Core/creative-phase-enforcement.mdc +145 -0
  6. data/.cursor/rules/isolation_rules/Core/creative-phase-metrics.mdc +195 -0
  7. data/.cursor/rules/isolation_rules/Core/file-verification.mdc +198 -0
  8. data/.cursor/rules/isolation_rules/Core/platform-awareness.mdc +71 -0
  9. data/.cursor/rules/isolation_rules/Level3/planning-comprehensive.mdc +159 -0
  10. data/.cursor/rules/isolation_rules/Level3/task-tracking-intermediate.mdc +135 -0
  11. data/.cursor/rules/isolation_rules/Phases/CreativePhase/creative-phase-architecture.mdc +187 -0
  12. data/.cursor/rules/isolation_rules/main.mdc +123 -0
  13. data/.cursor/rules/isolation_rules/visual-maps/archive-mode-map.mdc +277 -0
  14. data/.cursor/rules/isolation_rules/visual-maps/creative-mode-map.mdc +224 -0
  15. data/.cursor/rules/isolation_rules/visual-maps/implement-mode-map.mdc +321 -0
  16. data/.cursor/rules/isolation_rules/visual-maps/plan-mode-map.mdc +269 -0
  17. data/.cursor/rules/isolation_rules/visual-maps/qa-mode-map.mdc +495 -0
  18. data/.cursor/rules/isolation_rules/visual-maps/reflect-mode-map.mdc +234 -0
  19. data/.cursor/rules/isolation_rules/visual-maps/van-mode-map.mdc +902 -0
  20. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-complexity-determination.mdc +60 -0
  21. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-file-verification.mdc +49 -0
  22. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-mode-map.mdc +49 -0
  23. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-platform-detection.mdc +50 -0
  24. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/build-test.mdc +117 -0
  25. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/config-check.mdc +103 -0
  26. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/dependency-check.mdc +147 -0
  27. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/environment-check.mdc +104 -0
  28. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/file-verification.mdc +1 -0
  29. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-main.mdc +142 -0
  30. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/common-fixes.mdc +92 -0
  31. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/mode-transitions.mdc +101 -0
  32. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/reports.mdc +149 -0
  33. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/rule-calling-guide.mdc +66 -0
  34. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/rule-calling-help.mdc +19 -0
  35. data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-validation.md.old +363 -0
  36. data/.env.example +7 -0
  37. data/.memory_bank/activeContext.md +102 -0
  38. data/.memory_bank/progress.md +93 -0
  39. data/.memory_bank/projectbrief.md +45 -0
  40. data/.memory_bank/systemPatterns.md +90 -0
  41. data/.memory_bank/tasks.md +142 -0
  42. data/.memory_bank/techContext.md +73 -0
  43. data/.tool-versions +1 -0
  44. data/CHANGELOG.md +42 -0
  45. data/README.md +223 -5
  46. data/examples/function_calling.rb +218 -0
  47. data/examples/models_api.rb +125 -0
  48. data/examples/safety_settings.rb +82 -0
  49. data/lib/geminize/configuration.rb +4 -4
  50. data/lib/geminize/model_info.rb +87 -8
  51. data/lib/geminize/models/content_request_extensions.rb +219 -0
  52. data/lib/geminize/models/content_request_safety.rb +123 -0
  53. data/lib/geminize/models/content_response_extensions.rb +120 -0
  54. data/lib/geminize/models/function_declaration.rb +112 -0
  55. data/lib/geminize/models/function_response.rb +70 -0
  56. data/lib/geminize/models/model.rb +101 -109
  57. data/lib/geminize/models/model_list.rb +70 -28
  58. data/lib/geminize/models/safety_setting.rb +102 -0
  59. data/lib/geminize/models/tool.rb +47 -0
  60. data/lib/geminize/models/tool_config.rb +52 -0
  61. data/lib/geminize/module_extensions.rb +228 -0
  62. data/lib/geminize/module_safety.rb +135 -0
  63. data/lib/geminize/request_builder.rb +29 -0
  64. data/lib/geminize/version.rb +1 -1
  65. data/lib/geminize.rb +83 -14
  66. metadata +57 -2
@@ -4,69 +4,131 @@ module Geminize
4
4
  module Models
5
5
  # Represents an AI model from the Gemini API.
6
6
  class Model
7
- # @return [String] The unique identifier for the model
8
- attr_reader :id
9
-
10
- # @return [String] The display name of the model
7
+ # @return [String] The resource name of the model
11
8
  attr_reader :name
12
9
 
10
+ # @return [String] The base model ID
11
+ attr_reader :base_model_id
12
+
13
13
  # @return [String] The model version
14
14
  attr_reader :version
15
15
 
16
+ # @return [String] The display name of the model
17
+ attr_reader :display_name
18
+
16
19
  # @return [String] The model description
17
20
  attr_reader :description
18
21
 
19
- # @return [Array<String>] List of supported capabilities (e.g., 'text', 'vision', 'embedding')
20
- attr_reader :capabilities
22
+ # @return [Integer] Maximum number of input tokens allowed
23
+ attr_reader :input_token_limit
24
+
25
+ # @return [Integer] Maximum number of output tokens available
26
+ attr_reader :output_token_limit
21
27
 
22
- # @return [Hash] Model limitations and constraints
23
- attr_reader :limitations
28
+ # @return [Array<String>] Supported generation methods
29
+ attr_reader :supported_generation_methods
24
30
 
25
- # @return [Array<String>] Recommended use cases for this model
26
- attr_reader :use_cases
31
+ # @return [Float] Default temperature
32
+ attr_reader :temperature
33
+
34
+ # @return [Float] Maximum allowed temperature
35
+ attr_reader :max_temperature
36
+
37
+ # @return [Float] Default top_p value for nucleus sampling
38
+ attr_reader :top_p
39
+
40
+ # @return [Integer] Default top_k value for sampling
41
+ attr_reader :top_k
27
42
 
28
43
  # @return [Hash] Raw model data from the API
29
44
  attr_reader :raw_data
30
45
 
31
46
  # Create a new Model instance
32
47
  # @param attributes [Hash] Model attributes
33
- # @option attributes [String] :id The model ID
34
- # @option attributes [String] :name The model name
48
+ # @option attributes [String] :name The resource name of the model
49
+ # @option attributes [String] :base_model_id The base model ID
35
50
  # @option attributes [String] :version The model version
51
+ # @option attributes [String] :display_name The display name of the model
36
52
  # @option attributes [String] :description The model description
37
- # @option attributes [Array<String>] :capabilities List of capabilities
38
- # @option attributes [Hash] :limitations Model limitations
39
- # @option attributes [Array<String>] :use_cases Recommended use cases
53
+ # @option attributes [Integer] :input_token_limit Maximum input tokens
54
+ # @option attributes [Integer] :output_token_limit Maximum output tokens
55
+ # @option attributes [Array<String>] :supported_generation_methods Supported methods
56
+ # @option attributes [Float] :temperature Default temperature
57
+ # @option attributes [Float] :max_temperature Maximum temperature
58
+ # @option attributes [Float] :top_p Default top_p value
59
+ # @option attributes [Integer] :top_k Default top_k value
40
60
  # @option attributes [Hash] :raw_data Raw model data from API
41
61
  def initialize(attributes = {})
42
- @id = attributes[:id]
43
62
  @name = attributes[:name]
63
+ @base_model_id = attributes[:base_model_id]
44
64
  @version = attributes[:version]
65
+ @display_name = attributes[:display_name]
45
66
  @description = attributes[:description]
46
- @capabilities = attributes[:capabilities] || []
47
- @limitations = attributes[:limitations] || {}
48
- @use_cases = attributes[:use_cases] || []
67
+ @input_token_limit = attributes[:input_token_limit]
68
+ @output_token_limit = attributes[:output_token_limit]
69
+ @supported_generation_methods = attributes[:supported_generation_methods] || []
70
+ @temperature = attributes[:temperature]
71
+ @max_temperature = attributes[:max_temperature]
72
+ @top_p = attributes[:top_p]
73
+ @top_k = attributes[:top_k]
49
74
  @raw_data = attributes[:raw_data] || {}
50
75
  end
51
76
 
52
- # Check if model supports a specific capability
53
- # @param capability [String] Capability to check for
54
- # @return [Boolean] True if the model supports the capability
55
- def supports?(capability)
56
- capabilities.include?(capability.to_s.downcase)
77
+ # Shorthand accessor for the model ID (last part of the name path)
78
+ # @return [String] The model ID
79
+ def id
80
+ return nil unless @name
81
+ @name.split("/").last
82
+ end
83
+
84
+ # Check if model supports a specific generation method
85
+ # @param method [String] Generation method to check for
86
+ # @return [Boolean] True if the model supports the method
87
+ def supports_method?(method)
88
+ supported_generation_methods.include?(method.to_s)
89
+ end
90
+
91
+ # Check if model supports content generation
92
+ # @return [Boolean] True if the model supports content generation
93
+ def supports_content_generation?
94
+ supports_method?("generateContent")
95
+ end
96
+
97
+ # Check if model supports message generation (chat)
98
+ # @return [Boolean] True if the model supports message generation
99
+ def supports_message_generation?
100
+ supports_method?("generateMessage")
101
+ end
102
+
103
+ # Check if model supports embedding generation
104
+ # @return [Boolean] True if the model supports embedding generation
105
+ def supports_embedding?
106
+ supports_method?("embedContent")
107
+ end
108
+
109
+ # Check if model supports streaming content generation
110
+ # @return [Boolean] True if the model supports streaming content generation
111
+ def supports_streaming?
112
+ supports_method?("streamGenerateContent")
57
113
  end
58
114
 
59
115
  # Convert model to a hash representation
60
116
  # @return [Hash] Hash representation of the model
61
117
  def to_h
62
118
  {
63
- id: id,
64
119
  name: name,
120
+ id: id,
121
+ base_model_id: base_model_id,
65
122
  version: version,
123
+ display_name: display_name,
66
124
  description: description,
67
- capabilities: capabilities,
68
- limitations: limitations,
69
- use_cases: use_cases
125
+ input_token_limit: input_token_limit,
126
+ output_token_limit: output_token_limit,
127
+ supported_generation_methods: supported_generation_methods,
128
+ temperature: temperature,
129
+ max_temperature: max_temperature,
130
+ top_p: top_p,
131
+ top_k: top_k
70
132
  }
71
133
  end
72
134
 
@@ -80,92 +142,22 @@ module Geminize
80
142
  # @param data [Hash] Raw API response data
81
143
  # @return [Model] New Model instance
82
144
  def self.from_api_data(data)
83
- # Extract capabilities from model data
84
- capabilities = extract_capabilities(data)
85
-
86
- # Extract limitations from model data
87
- limitations = extract_limitations(data)
88
-
89
- # Extract use cases from model data
90
- use_cases = extract_use_cases(data)
91
-
92
145
  new(
93
- id: data["name"]&.split("/")&.last,
94
- name: data["displayName"],
95
- version: extract_version(data),
146
+ name: data["name"],
147
+ base_model_id: data["baseModelId"],
148
+ version: data["version"],
149
+ display_name: data["displayName"],
96
150
  description: data["description"],
97
- capabilities: capabilities,
98
- limitations: limitations,
99
- use_cases: use_cases,
151
+ input_token_limit: data["inputTokenLimit"],
152
+ output_token_limit: data["outputTokenLimit"],
153
+ supported_generation_methods: data["supportedGenerationMethods"] || [],
154
+ temperature: data["temperature"],
155
+ max_temperature: data["maxTemperature"],
156
+ top_p: data["topP"],
157
+ top_k: data["topK"],
100
158
  raw_data: data
101
159
  )
102
160
  end
103
-
104
- private_class_method def self.extract_version(data)
105
- # Extract version from model name or other fields
106
- # Example: if name is "gemini-1.0-pro", extract "1.0"
107
- if data["displayName"]
108
- match = data["displayName"].match(/[-_](\d+\.\d+)[-_]/)
109
- return match[1] if match
110
-
111
- # Try another pattern (e.g., "Gemini 1.5 Pro")
112
- match = data["displayName"].match(/\s(\d+\.\d+)\s/)
113
- return match[1] if match
114
- end
115
- nil
116
- end
117
-
118
- private_class_method def self.extract_capabilities(data)
119
- capabilities = []
120
-
121
- # Example capability extraction, adjust based on actual API response format
122
- capabilities << "text" if data.dig("supportedGenerationMethods")&.include?("generateText")
123
- capabilities << "chat" if data.dig("supportedGenerationMethods")&.include?("generateMessage")
124
- capabilities << "vision" if data.dig("supportedGenerationMethods")&.include?("generateContent") &&
125
- data.dig("inputSetting", "supportMultiModal")
126
- capabilities << "embedding" if data.dig("supportedGenerationMethods")&.include?("embedContent")
127
-
128
- capabilities
129
- end
130
-
131
- private_class_method def self.extract_limitations(data)
132
- limitations = {}
133
-
134
- # Extract token limits
135
- if data.dig("inputTokenLimit")
136
- limitations[:input_token_limit] = data["inputTokenLimit"]
137
- end
138
-
139
- if data.dig("outputTokenLimit")
140
- limitations[:output_token_limit] = data["outputTokenLimit"]
141
- end
142
-
143
- # Extract any other limitations from the API data
144
- limitations
145
- end
146
-
147
- private_class_method def self.extract_use_cases(data)
148
- # Extract use cases from the description or other fields
149
- # This is a simple implementation - adjust based on actual API data
150
- use_cases = []
151
-
152
- if data["description"]
153
- if data["description"].include?("chat")
154
- use_cases << "conversational_ai"
155
- end
156
-
157
- if data["description"].include?("vision") || data["description"].include?("image")
158
- use_cases << "image_understanding"
159
- end
160
-
161
- if data["description"].include?("embedding")
162
- use_cases << "semantic_search"
163
- use_cases << "clustering"
164
- end
165
- end
166
-
167
- use_cases
168
- end
169
161
  end
170
162
  end
171
163
  end
@@ -12,13 +12,18 @@ module Geminize
12
12
  # @return [Array<Model>] The list of models
13
13
  attr_reader :models
14
14
 
15
+ # @return [String, nil] Token for fetching the next page of results
16
+ attr_reader :next_page_token
17
+
15
18
  # Delegate array methods to the underlying models array
16
19
  def_delegators :@models, :[], :size, :length, :empty?, :first, :last
17
20
 
18
21
  # Create a new ModelList
19
22
  # @param models [Array<Model>] Initial list of models
20
- def initialize(models = [])
23
+ # @param next_page_token [String, nil] Token for fetching the next page
24
+ def initialize(models = [], next_page_token = nil)
21
25
  @models = models
26
+ @next_page_token = next_page_token
22
27
  end
23
28
 
24
29
  # Implement Enumerable's required each method
@@ -35,43 +40,50 @@ module Geminize
35
40
  self
36
41
  end
37
42
 
38
- # Find a model by its ID
43
+ # Find a model by its resource name
44
+ # @param name [String] The model name to search for
45
+ # @return [Model, nil] The found model or nil
46
+ def find_by_name(name)
47
+ @models.find { |model| model.name == name }
48
+ end
49
+
50
+ # Find a model by its ID (last part of the resource name)
39
51
  # @param id [String] The model ID to search for
40
52
  # @return [Model, nil] The found model or nil
41
53
  def find_by_id(id)
42
54
  @models.find { |model| model.id == id }
43
55
  end
44
56
 
45
- # Find all models that support a specific capability
46
- # @param capability [String] The capability to filter by
57
+ # Find all models that support a specific generation method
58
+ # @param method [String] The generation method to filter by
47
59
  # @return [ModelList] A new ModelList containing only matching models
48
- def filter_by_capability(capability)
49
- filtered = @models.select { |model| model.supports?(capability) }
50
- ModelList.new(filtered)
60
+ def filter_by_method(method)
61
+ filtered = @models.select { |model| model.supports_method?(method) }
62
+ ModelList.new(filtered, nil)
51
63
  end
52
64
 
53
- # Find all models that support vision capabilities
54
- # @return [ModelList] A new ModelList containing only vision-capable models
55
- def vision_models
56
- filter_by_capability("vision")
65
+ # Find all models that support content generation
66
+ # @return [ModelList] A new ModelList containing only content generation capable models
67
+ def content_generation_models
68
+ filter_by_method("generateContent")
57
69
  end
58
70
 
59
- # Find all models that support embedding capabilities
60
- # @return [ModelList] A new ModelList containing only embedding-capable models
61
- def embedding_models
62
- filter_by_capability("embedding")
71
+ # Find all models that support streaming content generation
72
+ # @return [ModelList] A new ModelList containing only streaming capable models
73
+ def streaming_models
74
+ filter_by_method("streamGenerateContent")
63
75
  end
64
76
 
65
- # Find all models that support text generation
66
- # @return [ModelList] A new ModelList containing only text generation models
67
- def text_models
68
- filter_by_capability("text")
77
+ # Find all models that support embeddings
78
+ # @return [ModelList] A new ModelList containing only embedding-capable models
79
+ def embedding_models
80
+ filter_by_method("embedContent")
69
81
  end
70
82
 
71
83
  # Find all models that support chat/conversation
72
84
  # @return [ModelList] A new ModelList containing only chat-capable models
73
85
  def chat_models
74
- filter_by_capability("chat")
86
+ filter_by_method("generateMessage")
75
87
  end
76
88
 
77
89
  # Filter models by version
@@ -79,16 +91,40 @@ module Geminize
79
91
  # @return [ModelList] A new ModelList containing only matching models
80
92
  def filter_by_version(version)
81
93
  filtered = @models.select { |model| model.version == version }
82
- ModelList.new(filtered)
94
+ ModelList.new(filtered, nil)
83
95
  end
84
96
 
85
- # Filter models by name pattern
86
- # @param pattern [String, Regexp] The pattern to match model names against
97
+ # Filter models by display name pattern
98
+ # @param pattern [String, Regexp] The pattern to match model display names against
87
99
  # @return [ModelList] A new ModelList containing only matching models
88
- def filter_by_name(pattern)
100
+ def filter_by_display_name(pattern)
89
101
  pattern = Regexp.new(pattern.to_s, Regexp::IGNORECASE) if pattern.is_a?(String)
90
- filtered = @models.select { |model| model.name&.match?(pattern) }
91
- ModelList.new(filtered)
102
+ filtered = @models.select { |model| model.display_name&.match?(pattern) }
103
+ ModelList.new(filtered, nil)
104
+ end
105
+
106
+ # Filter models by base model ID
107
+ # @param base_model_id [String] The base model ID to filter by
108
+ # @return [ModelList] A new ModelList containing only matching models
109
+ def filter_by_base_model_id(base_model_id)
110
+ filtered = @models.select { |model| model.base_model_id == base_model_id }
111
+ ModelList.new(filtered, nil)
112
+ end
113
+
114
+ # Find models with a minimum input token limit
115
+ # @param min_limit [Integer] The minimum input token limit
116
+ # @return [ModelList] A new ModelList containing only matching models
117
+ def filter_by_min_input_tokens(min_limit)
118
+ filtered = @models.select { |model| model.input_token_limit && model.input_token_limit >= min_limit }
119
+ ModelList.new(filtered, nil)
120
+ end
121
+
122
+ # Find models with a minimum output token limit
123
+ # @param min_limit [Integer] The minimum output token limit
124
+ # @return [ModelList] A new ModelList containing only matching models
125
+ def filter_by_min_output_tokens(min_limit)
126
+ filtered = @models.select { |model| model.output_token_limit && model.output_token_limit >= min_limit }
127
+ ModelList.new(filtered, nil)
92
128
  end
93
129
 
94
130
  # Create a ModelList from API response data
@@ -96,16 +132,22 @@ module Geminize
96
132
  # @return [ModelList] New ModelList instance
97
133
  def self.from_api_data(data)
98
134
  models = []
135
+ next_page_token = data["nextPageToken"]
99
136
 
100
137
  # Process model data from API response
101
- # The exact structure will depend on the Gemini API response format
102
138
  if data.key?("models")
103
139
  models = data["models"].map do |model_data|
104
140
  Model.from_api_data(model_data)
105
141
  end
106
142
  end
107
143
 
108
- new(models)
144
+ new(models, next_page_token)
145
+ end
146
+
147
+ # Check if there are more pages of results available
148
+ # @return [Boolean] True if there are more pages
149
+ def has_more_pages?
150
+ !next_page_token.nil? && !next_page_token.empty?
109
151
  end
110
152
 
111
153
  # Convert to array of hashes representation
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geminize
4
+ module Models
5
+ # Represents a safety setting for content filtering in Gemini API
6
+ class SafetySetting
7
+ # Valid harm categories for safety settings
8
+ HARM_CATEGORIES = [
9
+ "HARM_CATEGORY_HARASSMENT",
10
+ "HARM_CATEGORY_HATE_SPEECH",
11
+ "HARM_CATEGORY_SEXUALLY_EXPLICIT",
12
+ "HARM_CATEGORY_DANGEROUS_CONTENT"
13
+ ].freeze
14
+
15
+ # Valid threshold levels for safety settings
16
+ THRESHOLD_LEVELS = [
17
+ "BLOCK_NONE",
18
+ "BLOCK_LOW_AND_ABOVE",
19
+ "BLOCK_MEDIUM_AND_ABOVE",
20
+ "BLOCK_ONLY_HIGH"
21
+ ].freeze
22
+
23
+ # @return [String] The harm category this setting applies to
24
+ attr_reader :category
25
+
26
+ # @return [String] The threshold level for filtering
27
+ attr_reader :threshold
28
+
29
+ # Initialize a new safety setting
30
+ # @param category [String] The harm category this setting applies to
31
+ # @param threshold [String] The threshold level for filtering
32
+ # @raise [Geminize::ValidationError] If the safety setting is invalid
33
+ def initialize(category, threshold)
34
+ @category = category
35
+ @threshold = threshold
36
+ validate!
37
+ end
38
+
39
+ # Validate the safety setting
40
+ # @raise [Geminize::ValidationError] If the safety setting is invalid
41
+ # @return [Boolean] true if validation passes
42
+ def validate!
43
+ validate_category!
44
+ validate_threshold!
45
+ true
46
+ end
47
+
48
+ # Convert the safety setting to a hash for API requests
49
+ # @return [Hash] The safety setting as a hash
50
+ def to_hash
51
+ {
52
+ category: @category,
53
+ threshold: @threshold
54
+ }
55
+ end
56
+
57
+ # Alias for to_hash
58
+ # @return [Hash] The safety setting as a hash
59
+ def to_h
60
+ to_hash
61
+ end
62
+
63
+ private
64
+
65
+ # Validate the harm category
66
+ # @raise [Geminize::ValidationError] If the category is invalid
67
+ def validate_category!
68
+ unless @category.is_a?(String)
69
+ raise Geminize::ValidationError.new(
70
+ "Category must be a string, got #{@category.class}",
71
+ "INVALID_ARGUMENT"
72
+ )
73
+ end
74
+
75
+ unless HARM_CATEGORIES.include?(@category)
76
+ raise Geminize::ValidationError.new(
77
+ "Invalid harm category: #{@category}. Must be one of: #{HARM_CATEGORIES.join(", ")}",
78
+ "INVALID_ARGUMENT"
79
+ )
80
+ end
81
+ end
82
+
83
+ # Validate the threshold level
84
+ # @raise [Geminize::ValidationError] If the threshold is invalid
85
+ def validate_threshold!
86
+ unless @threshold.is_a?(String)
87
+ raise Geminize::ValidationError.new(
88
+ "Threshold must be a string, got #{@threshold.class}",
89
+ "INVALID_ARGUMENT"
90
+ )
91
+ end
92
+
93
+ unless THRESHOLD_LEVELS.include?(@threshold)
94
+ raise Geminize::ValidationError.new(
95
+ "Invalid threshold level: #{@threshold}. Must be one of: #{THRESHOLD_LEVELS.join(", ")}",
96
+ "INVALID_ARGUMENT"
97
+ )
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geminize
4
+ module Models
5
+ # Represents a tool for function calling in Gemini API
6
+ class Tool
7
+ # @return [Geminize::Models::FunctionDeclaration] The function declaration for this tool
8
+ attr_reader :function_declaration
9
+
10
+ # Initialize a new tool
11
+ # @param function_declaration [Geminize::Models::FunctionDeclaration] The function declaration
12
+ # @raise [Geminize::ValidationError] If the tool is invalid
13
+ def initialize(function_declaration)
14
+ @function_declaration = function_declaration
15
+ validate!
16
+ end
17
+
18
+ # Validate the tool
19
+ # @raise [Geminize::ValidationError] If the tool is invalid
20
+ # @return [Boolean] true if validation passes
21
+ def validate!
22
+ unless @function_declaration.is_a?(Geminize::Models::FunctionDeclaration)
23
+ raise Geminize::ValidationError.new(
24
+ "Function declaration must be a FunctionDeclaration, got #{@function_declaration.class}",
25
+ "INVALID_ARGUMENT"
26
+ )
27
+ end
28
+
29
+ true
30
+ end
31
+
32
+ # Convert the tool to a hash for API requests
33
+ # @return [Hash] The tool as a hash
34
+ def to_hash
35
+ {
36
+ functionDeclarations: @function_declaration.to_hash
37
+ }
38
+ end
39
+
40
+ # Alias for to_hash
41
+ # @return [Hash] The tool as a hash
42
+ def to_h
43
+ to_hash
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geminize
4
+ module Models
5
+ # Represents configuration for tool execution in Gemini API
6
+ class ToolConfig
7
+ # Valid execution modes for tools
8
+ EXECUTION_MODES = ["AUTO", "MANUAL", "NONE"].freeze
9
+
10
+ # @return [String] The execution mode for tools
11
+ attr_reader :execution_mode
12
+
13
+ # Initialize a new tool configuration
14
+ # @param execution_mode [String] The execution mode for tools
15
+ # @raise [Geminize::ValidationError] If the tool configuration is invalid
16
+ def initialize(execution_mode = "AUTO")
17
+ @execution_mode = execution_mode
18
+ validate!
19
+ end
20
+
21
+ # Validate the tool configuration
22
+ # @raise [Geminize::ValidationError] If the tool configuration is invalid
23
+ # @return [Boolean] true if validation passes
24
+ def validate!
25
+ unless EXECUTION_MODES.include?(@execution_mode)
26
+ raise Geminize::ValidationError.new(
27
+ "Invalid execution mode: #{@execution_mode}. Must be one of: #{EXECUTION_MODES.join(", ")}",
28
+ "INVALID_ARGUMENT"
29
+ )
30
+ end
31
+
32
+ true
33
+ end
34
+
35
+ # Convert the tool configuration to a hash for API requests
36
+ # @return [Hash] The tool configuration as a hash
37
+ def to_hash
38
+ {
39
+ function_calling_config: {
40
+ mode: @execution_mode
41
+ }
42
+ }
43
+ end
44
+
45
+ # Alias for to_hash
46
+ # @return [Hash] The tool configuration as a hash
47
+ def to_h
48
+ to_hash
49
+ end
50
+ end
51
+ end
52
+ end