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
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "geminize"
6
+ require "json"
7
+
8
+ # Configure the API key
9
+ Geminize.configure do |config|
10
+ config.api_key = ENV["GEMINI_API_KEY"] # Make sure to set your API key in the environment
11
+ config.default_model = "gemini-1.5-pro-latest" # Use the latest model that supports function calling
12
+ end
13
+
14
+ # Define a weather function that can handle a location and unit
15
+ def get_weather(location, unit = "celsius")
16
+ puts "Getting weather for #{location} in #{unit}..."
17
+
18
+ # In a real implementation, this would call a weather API
19
+ # For this example, we'll return mock data
20
+ case location.downcase
21
+ when /new york/
22
+ {temperature: (unit == "celsius") ? 22 : 72, conditions: "Sunny", humidity: 45}
23
+ when /london/
24
+ {temperature: (unit == "celsius") ? 15 : 59, conditions: "Rainy", humidity: 80}
25
+ when /tokyo/
26
+ {temperature: (unit == "celsius") ? 26 : 79, conditions: "Partly Cloudy", humidity: 65}
27
+ else
28
+ {temperature: (unit == "celsius") ? 20 : 68, conditions: "Unknown", humidity: 50}
29
+ end
30
+ end
31
+
32
+ # Enhanced weather function that can handle a batch of locations
33
+ def get_weather_batch(locations, unit = "celsius")
34
+ if locations.is_a?(Array)
35
+ results = {}
36
+ locations.each do |location|
37
+ results[location] = get_weather(location, unit)
38
+ end
39
+ results
40
+ else
41
+ {locations => get_weather(locations, unit)}
42
+ end
43
+ end
44
+
45
+ # Define a function schema for get_weather
46
+ weather_function = {
47
+ name: "get_weather",
48
+ description: "Get the current weather in a location",
49
+ parameters: {
50
+ type: "object",
51
+ properties: {
52
+ location: {
53
+ type: "string",
54
+ description: "The city and state or country, e.g., 'New York, NY' or 'London, UK'"
55
+ },
56
+ unit: {
57
+ type: "string",
58
+ enum: ["celsius", "fahrenheit"],
59
+ description: "The unit of temperature"
60
+ }
61
+ },
62
+ required: ["location"]
63
+ }
64
+ }
65
+
66
+ # Define a batch weather function schema that can handle multiple locations
67
+ batch_weather_function = {
68
+ name: "get_weather_batch",
69
+ description: "Get the current weather for multiple locations at once",
70
+ parameters: {
71
+ type: "object",
72
+ properties: {
73
+ locations: {
74
+ type: "array",
75
+ items: {
76
+ type: "string"
77
+ },
78
+ description: "List of cities, e.g., ['New York, NY', 'London, UK', 'Tokyo, Japan']"
79
+ },
80
+ unit: {
81
+ type: "string",
82
+ enum: ["celsius", "fahrenheit"],
83
+ description: "The unit of temperature"
84
+ }
85
+ },
86
+ required: ["locations"]
87
+ }
88
+ }
89
+
90
+ puts "==========================================="
91
+ puts "= GEMINIZE FUNCTION CALLING & JSON EXAMPLES ="
92
+ puts "==========================================="
93
+
94
+ puts "\n=== FUNCTION CALLING EXAMPLE ==="
95
+ puts "Asking Gemini about the weather in New York..."
96
+
97
+ begin
98
+ # Generate a response with the function definition
99
+ response = Geminize.generate_with_functions(
100
+ "What's the weather like in New York?",
101
+ [weather_function],
102
+ nil,
103
+ {temperature: 0.2}
104
+ )
105
+
106
+ # Check if the model wants to call a function
107
+ if response.has_function_call?
108
+ function_call = response.function_call
109
+ puts "Model wants to call function: #{function_call.name}"
110
+ puts "With arguments: #{function_call.response.inspect}"
111
+
112
+ function_name = function_call.name
113
+ args = function_call.response
114
+
115
+ if function_name == "get_weather"
116
+ location = args["location"]
117
+ unit = args["unit"] || "celsius"
118
+
119
+ # Call our weather function
120
+ weather_data = get_weather(location, unit)
121
+ puts "Weather data for #{location}: #{weather_data.inspect}"
122
+
123
+ # Process the function result
124
+ final_response = Geminize.process_function_call(response) do |name, arguments|
125
+ get_weather(arguments["location"], arguments["unit"])
126
+ end
127
+
128
+ puts "\nFinal response from Gemini:"
129
+ puts final_response.text
130
+ else
131
+ puts "Unexpected function call: #{function_name}"
132
+ end
133
+ else
134
+ puts "Model did not request to call a function."
135
+ puts "Response: #{response.text}"
136
+ end
137
+ rescue => e
138
+ puts "Error during function calling: #{e.message}"
139
+ end
140
+
141
+ # Example of using JSON mode
142
+ puts "\n\n=== JSON MODE EXAMPLE ==="
143
+ puts "Using JSON mode to get weather data in structured format..."
144
+
145
+ begin
146
+ json_response = Geminize.generate_json(
147
+ "Get the current temperature and weather conditions for New York.",
148
+ nil,
149
+ {
150
+ system_instruction: "Return a JSON object with temperature in celsius and conditions."
151
+ }
152
+ )
153
+
154
+ if json_response.has_json_response?
155
+ puts "Structured JSON response:"
156
+ puts JSON.pretty_generate(json_response.json_response)
157
+ else
158
+ puts "Raw text response (not valid JSON):"
159
+ puts json_response.text
160
+ end
161
+ rescue => e
162
+ puts "Error during JSON mode: #{e.message}"
163
+ end
164
+
165
+ puts "\n\n=== BATCH FUNCTION CALL EXAMPLE ==="
166
+ puts "Using batch function to efficiently get weather for multiple cities at once..."
167
+
168
+ begin
169
+ # Use a batch function to get all cities at once (more efficient)
170
+ response = Geminize.generate_with_functions(
171
+ "I need weather information for New York, Tokyo, and London. Please get all this information in a single function call.",
172
+ [batch_weather_function],
173
+ nil,
174
+ {temperature: 0.2}
175
+ )
176
+
177
+ # Check if the model wants to call the batch function
178
+ if response.has_function_call?
179
+ function_call = response.function_call
180
+ puts "Model wants to call function: #{function_call.name}"
181
+ puts "With arguments: #{function_call.response.inspect}"
182
+
183
+ function_name = function_call.name
184
+ args = function_call.response
185
+
186
+ if function_name == "get_weather_batch"
187
+ locations = args["locations"]
188
+ unit = args["unit"] || "celsius"
189
+
190
+ # Get weather for all locations at once
191
+ weather_data = get_weather_batch(locations, unit)
192
+ puts "Weather data for multiple locations: #{weather_data.inspect}"
193
+
194
+ # Process the function result with a single API call
195
+ final_response = Geminize.process_function_call(response) do |name, arguments|
196
+ get_weather_batch(arguments["locations"], arguments["unit"])
197
+ end
198
+
199
+ puts "\nFinal response from Gemini:"
200
+ puts final_response.text
201
+ else
202
+ puts "Unexpected function call: #{function_name}"
203
+ end
204
+ else
205
+ puts "Model did not request to call a function."
206
+ puts "Response: #{response.text}"
207
+ end
208
+ rescue => e
209
+ puts "Error during batch function calling: #{e.message}"
210
+ puts "\nNOTE: If you hit a quota limit, try:"
211
+ puts "1. Using a paid API key with higher quotas"
212
+ puts "2. Reducing the number of examples you run"
213
+ puts "3. Adding delays between API calls"
214
+ end
215
+
216
+ puts "\n==========================================="
217
+ puts "= END OF EXAMPLES ="
218
+ puts "==========================================="
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "geminize"
6
+ require "pp"
7
+
8
+ # Configure the library with your API key
9
+ Geminize.configure do |config|
10
+ # Load API key from .env file or environment variables
11
+ config.api_key = ENV["GEMINI_API_KEY"]
12
+ # Use the latest API version
13
+ config.api_version = "v1beta"
14
+ end
15
+
16
+ # Helper method to display model information
17
+ def display_model(model)
18
+ puts "========================"
19
+ puts "Model: #{model.display_name} (#{model.name})"
20
+ puts "Base Model ID: #{model.base_model_id}"
21
+ puts "Version: #{model.version}"
22
+ puts "Description: #{model.description}"
23
+ puts "Input Token Limit: #{model.input_token_limit}"
24
+ puts "Output Token Limit: #{model.output_token_limit}"
25
+ puts "Temperature: #{model.temperature}"
26
+ puts "Max Temperature: #{model.max_temperature}"
27
+ puts "Top P: #{model.top_p}"
28
+ puts "Top K: #{model.top_k}"
29
+ puts "Supported Methods: #{model.supported_generation_methods.join(", ")}"
30
+ puts "Capabilities:"
31
+ puts " - Content Generation: #{model.supports_content_generation?}"
32
+ puts " - Chat: #{model.supports_message_generation?}"
33
+ puts " - Embedding: #{model.supports_embedding?}"
34
+ puts " - Streaming: #{model.supports_streaming?}"
35
+ puts "========================\n\n"
36
+ end
37
+
38
+ puts "=== MODELS API EXAMPLES ==="
39
+
40
+ # Example 1: List models (first page)
41
+ puts "\n=== Example 1: List first page of models ==="
42
+ begin
43
+ model_list = Geminize.list_models(page_size: 5)
44
+ puts "Found #{model_list.size} models on first page"
45
+ puts "Has more pages: #{model_list.has_more_pages?}"
46
+ puts "Next page token: #{model_list.next_page_token}"
47
+ puts "\nFirst model details:"
48
+ display_model(model_list.first) if model_list.first
49
+ rescue => e
50
+ puts "Error listing models: #{e.message}"
51
+ end
52
+
53
+ # Example 2: Get detailed info for a specific model
54
+ puts "\n=== Example 2: Get specific model info ==="
55
+ begin
56
+ model = Geminize.get_model("gemini-1.5-flash")
57
+ puts "Retrieved model details:"
58
+ display_model(model)
59
+ rescue => e
60
+ puts "Error getting model: #{e.message}"
61
+ end
62
+
63
+ # Example 3: Get all models (handling pagination)
64
+ puts "\n=== Example 3: Get all models (handling pagination) ==="
65
+ begin
66
+ all_models = Geminize.list_all_models
67
+ puts "Retrieved #{all_models.size} models in total"
68
+ rescue => e
69
+ puts "Error listing all models: #{e.message}"
70
+ end
71
+
72
+ # Example 4: Filter models by capability
73
+ puts "\n=== Example 4: Filter models by capability ==="
74
+ begin
75
+ # Get models that support embedding
76
+ embedding_models = Geminize.get_embedding_models
77
+ puts "Found #{embedding_models.size} models that support embeddings"
78
+
79
+ # Get models that support content generation
80
+ content_models = Geminize.get_content_generation_models
81
+ puts "Found #{content_models.size} models that support content generation"
82
+
83
+ # Get models that support chat
84
+ chat_models = Geminize.get_chat_models
85
+ puts "Found #{chat_models.size} models that support chat"
86
+
87
+ # Get models that support streaming
88
+ streaming_models = Geminize.get_streaming_models
89
+ puts "Found #{streaming_models.size} models that support streaming"
90
+ rescue => e
91
+ puts "Error filtering models: #{e.message}"
92
+ end
93
+
94
+ # Example 5: Filter models by specific method
95
+ puts "\n=== Example 5: Filter models by specific method ==="
96
+ begin
97
+ method_models = Geminize.get_models_by_method("generateContent")
98
+ puts "Found #{method_models.size} models that support generateContent"
99
+
100
+ # Display a specific model from the filtered list
101
+ if method_models.size > 0
102
+ puts "\nExample of a model supporting generateContent:"
103
+ display_model(method_models.first)
104
+ end
105
+ rescue => e
106
+ puts "Error filtering by method: #{e.message}"
107
+ end
108
+
109
+ # Example 6: Model comparison
110
+ puts "\n=== Example 6: Compare token limits ==="
111
+ begin
112
+ all_models = Geminize.list_all_models
113
+
114
+ # Filter to models with higher token limits
115
+ high_capacity_models = all_models.filter_by_min_input_tokens(100_000)
116
+
117
+ puts "Models with 100k+ input token limits:"
118
+ high_capacity_models.each do |model|
119
+ puts " - #{model.display_name}: #{model.input_token_limit} input tokens"
120
+ end
121
+ rescue => e
122
+ puts "Error comparing models: #{e.message}"
123
+ end
124
+
125
+ puts "\n=== Examples Complete ==="
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "geminize"
6
+
7
+ # Configure the API key
8
+ Geminize.configure do |config|
9
+ config.api_key = ENV["GEMINI_API_KEY"] # Make sure to set your API key in the environment
10
+ config.default_model = "gemini-1.5-pro-latest" # Use the latest model
11
+ end
12
+
13
+ # A prompt that might trigger safety filters
14
+ POTENTIALLY_SENSITIVE_PROMPT = "Describe a violent conflict scene from a movie"
15
+
16
+ puts "1. Generating with default safety settings:"
17
+ begin
18
+ response = Geminize.generate_text(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
19
+ puts "Default response:\n#{response.text}\n\n"
20
+ rescue Geminize::GeminizeError => e
21
+ puts "Error with default settings: #{e.message}\n\n"
22
+ end
23
+
24
+ puts "2. Generating with maximum safety (blocking most potentially harmful content):"
25
+ begin
26
+ response = Geminize.generate_text_safe(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
27
+ puts "Maximum safety response:\n#{response.text}\n\n"
28
+ rescue Geminize::GeminizeError => e
29
+ puts "Error with maximum safety: #{e.message}\n\n"
30
+ end
31
+
32
+ puts "3. Generating with minimum safety (blocking only high-risk content):"
33
+ begin
34
+ response = Geminize.generate_text_permissive(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
35
+ puts "Minimum safety response:\n#{response.text}\n\n"
36
+ rescue Geminize::GeminizeError => e
37
+ puts "Error with minimum safety: #{e.message}\n\n"
38
+ end
39
+
40
+ puts "4. Generating with custom safety settings:"
41
+ begin
42
+ # Custom safety settings:
43
+ # - Block medium and above for dangerous content
44
+ # - Block low and above for hate speech
45
+ # - Block only high for sexually explicit content
46
+ # - No blocks for harassment
47
+ custom_safety_settings = [
48
+ {category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_MEDIUM_AND_ABOVE"},
49
+ {category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_LOW_AND_ABOVE"},
50
+ {category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_ONLY_HIGH"},
51
+ {category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE"}
52
+ ]
53
+
54
+ response = Geminize.generate_with_safety_settings(
55
+ POTENTIALLY_SENSITIVE_PROMPT,
56
+ custom_safety_settings,
57
+ nil,
58
+ temperature: 0.2
59
+ )
60
+ puts "Custom safety response:\n#{response.text}\n\n"
61
+ rescue Geminize::GeminizeError => e
62
+ puts "Error with custom safety: #{e.message}\n\n"
63
+ end
64
+
65
+ # Demonstrate direct usage of safety settings in a ContentRequest
66
+ puts "5. Using safety settings directly in a ContentRequest:"
67
+ begin
68
+ generator = Geminize::TextGeneration.new
69
+ content_request = Geminize::Models::ContentRequest.new(
70
+ POTENTIALLY_SENSITIVE_PROMPT,
71
+ nil,
72
+ temperature: 0.2
73
+ )
74
+
75
+ # Add specific safety settings
76
+ content_request.add_safety_setting("HARM_CATEGORY_DANGEROUS_CONTENT", "BLOCK_MEDIUM_AND_ABOVE")
77
+
78
+ response = generator.generate(content_request)
79
+ puts "ContentRequest safety response:\n#{response.text}\n\n"
80
+ rescue Geminize::GeminizeError => e
81
+ puts "Error with ContentRequest safety: #{e.message}\n\n"
82
+ end
@@ -17,7 +17,7 @@ module Geminize
17
17
  DEFAULT_MODEL = "gemini-2.0-flash"
18
18
 
19
19
  # Default embedding model
20
- DEFAULT_EMBEDDING_MODEL = "embedding-001"
20
+ DEFAULT_EMBEDDING_MODEL = "gemini-embedding-exp-03-07"
21
21
 
22
22
  # Default timeout values (in seconds)
23
23
  DEFAULT_TIMEOUT = 30
@@ -69,9 +69,9 @@ module Geminize
69
69
  # @return [void]
70
70
  def reset!
71
71
  @api_key = ENV["GEMINI_API_KEY"]
72
- @api_version = DEFAULT_API_VERSION
73
- @default_model = DEFAULT_MODEL
74
- @default_embedding_model = DEFAULT_EMBEDDING_MODEL
72
+ @api_version = ENV["GEMINI_API_VERSION"] || DEFAULT_API_VERSION
73
+ @default_model = ENV["GEMINI_MODEL"] || DEFAULT_MODEL
74
+ @default_embedding_model = ENV["GEMINI_EMBEDDING_MODEL"] || DEFAULT_EMBEDDING_MODEL
75
75
  @timeout = DEFAULT_TIMEOUT
76
76
  @open_timeout = DEFAULT_OPEN_TIMEOUT
77
77
  @streaming_timeout = DEFAULT_STREAMING_TIMEOUT
@@ -9,6 +9,9 @@ module Geminize
9
9
  # @return [Geminize::Client] The HTTP client
10
10
  attr_reader :client
11
11
 
12
+ # Default page size for listing models
13
+ DEFAULT_PAGE_SIZE = 50
14
+
12
15
  # Initialize a new ModelInfo instance
13
16
  # @param client [Geminize::Client, nil] The HTTP client to use
14
17
  # @param options [Hash] Additional options for the client
@@ -20,19 +23,26 @@ module Geminize
20
23
  end
21
24
 
22
25
  # List available models from the Gemini API
26
+ # @param page_size [Integer, nil] Number of models to return per page (max 1000)
27
+ # @param page_token [String, nil] Token for retrieving a specific page
23
28
  # @param force_refresh [Boolean] Force a refresh from the API instead of using cache
24
29
  # @return [Geminize::Models::ModelList] List of available models
25
30
  # @raise [Geminize::GeminizeError] If the request fails
26
- def list_models(force_refresh: false)
27
- cache_key = "models_list"
31
+ def list_models(page_size: nil, page_token: nil, force_refresh: false)
32
+ cache_key = "models_list_#{page_size}_#{page_token}"
28
33
 
29
34
  # Check if we have a valid cached result
30
35
  if !force_refresh && @cache[cache_key] && @cache_expiry[cache_key] > Time.now
31
36
  return @cache[cache_key]
32
37
  end
33
38
 
39
+ # Prepare query parameters
40
+ params = {}
41
+ params[:pageSize] = page_size if page_size
42
+ params[:pageToken] = page_token
43
+
34
44
  # Make the API request
35
- response = client.get("models")
45
+ response = client.get("models", params)
36
46
 
37
47
  # Create a ModelList from the response
38
48
  model_list = Models::ModelList.from_api_data(response)
@@ -44,13 +54,62 @@ module Geminize
44
54
  model_list
45
55
  end
46
56
 
57
+ # Get all available models, handling pagination automatically
58
+ # @param force_refresh [Boolean] Force a refresh from the API instead of using cache
59
+ # @return [Geminize::Models::ModelList] Complete list of all available models
60
+ # @raise [Geminize::GeminizeError] If any request fails
61
+ def list_all_models(force_refresh: false)
62
+ cache_key = "all_models_list"
63
+
64
+ # Check if we have a valid cached result
65
+ if !force_refresh && @cache[cache_key] && @cache_expiry[cache_key] > Time.now
66
+ return @cache[cache_key]
67
+ end
68
+
69
+ all_models = []
70
+ page_token = nil
71
+
72
+ # Fetch first page
73
+ model_list = list_models(
74
+ page_size: DEFAULT_PAGE_SIZE,
75
+ page_token: page_token,
76
+ force_refresh: force_refresh
77
+ )
78
+ all_models.concat(model_list.models)
79
+
80
+ # Fetch additional pages if available
81
+ while model_list.has_more_pages?
82
+ page_token = model_list.next_page_token
83
+ model_list = list_models(
84
+ page_size: DEFAULT_PAGE_SIZE,
85
+ page_token: page_token,
86
+ force_refresh: force_refresh
87
+ )
88
+ all_models.concat(model_list.models)
89
+ end
90
+
91
+ # Create a consolidated model list
92
+ result = Models::ModelList.new(all_models)
93
+
94
+ # Cache the result
95
+ @cache[cache_key] = result
96
+ @cache_expiry[cache_key] = Time.now + @cache_ttl
97
+
98
+ result
99
+ end
100
+
47
101
  # Get information about a specific model
48
- # @param model_id [String] The model ID to retrieve
102
+ # @param model_name [String] The model name to retrieve (models/{model})
49
103
  # @param force_refresh [Boolean] Force a refresh from the API instead of using cache
50
104
  # @return [Geminize::Models::Model] The model information
51
105
  # @raise [Geminize::GeminizeError] If the request fails or model is not found
52
- def get_model(model_id, force_refresh: false)
53
- cache_key = "model_#{model_id}"
106
+ def get_model(model_name, force_refresh: false)
107
+ # Handle both formats: "models/gemini-1.5-pro" or just "gemini-1.5-pro"
108
+ unless model_name.start_with?("models/")
109
+ model_name = "models/#{model_name}"
110
+ end
111
+
112
+ cache_key = "model_#{model_name}"
54
113
 
55
114
  # Check if we have a valid cached result
56
115
  if !force_refresh && @cache[cache_key] && @cache_expiry[cache_key] > Time.now
@@ -59,7 +118,7 @@ module Geminize
59
118
 
60
119
  # Make the API request
61
120
  begin
62
- response = client.get("models/#{model_id}")
121
+ response = client.get(model_name)
63
122
 
64
123
  # Create a Model from the response
65
124
  model = Models::Model.from_api_data(response)
@@ -71,10 +130,30 @@ module Geminize
71
130
  model
72
131
  rescue Geminize::NotFoundError => e
73
132
  # Re-raise with a more descriptive message
74
- raise Geminize::NotFoundError.new("Model '#{model_id}' not found", e.code, e.http_status)
133
+ raise Geminize::NotFoundError.new("Model '#{model_name}' not found", e.code, e.http_status)
75
134
  end
76
135
  end
77
136
 
137
+ # Get models that support a specific generation method
138
+ # @param method [String] The generation method (e.g., "generateContent", "embedContent")
139
+ # @param force_refresh [Boolean] Force a refresh from the API instead of using cache
140
+ # @return [Geminize::Models::ModelList] List of models that support the method
141
+ # @raise [Geminize::GeminizeError] If the request fails
142
+ def get_models_by_method(method, force_refresh: false)
143
+ all_models = list_all_models(force_refresh: force_refresh)
144
+ all_models.filter_by_method(method)
145
+ end
146
+
147
+ # Get models by base model ID
148
+ # @param base_model_id [String] The base model ID to filter by
149
+ # @param force_refresh [Boolean] Force a refresh from the API instead of using cache
150
+ # @return [Geminize::Models::ModelList] List of models with the specified base model ID
151
+ # @raise [Geminize::GeminizeError] If the request fails
152
+ def get_models_by_base_id(base_model_id, force_refresh: false)
153
+ all_models = list_all_models(force_refresh: force_refresh)
154
+ all_models.filter_by_base_model_id(base_model_id)
155
+ end
156
+
78
157
  # Clear all cached model information
79
158
  # @return [void]
80
159
  def clear_cache