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.
- checksums.yaml +4 -4
 - data/.cursor/mcp.json +3 -0
 - data/.cursor/rules/isolation_rules/Core/command-execution.mdc +235 -0
 - data/.cursor/rules/isolation_rules/Core/complexity-decision-tree.mdc +187 -0
 - data/.cursor/rules/isolation_rules/Core/creative-phase-enforcement.mdc +145 -0
 - data/.cursor/rules/isolation_rules/Core/creative-phase-metrics.mdc +195 -0
 - data/.cursor/rules/isolation_rules/Core/file-verification.mdc +198 -0
 - data/.cursor/rules/isolation_rules/Core/platform-awareness.mdc +71 -0
 - data/.cursor/rules/isolation_rules/Level3/planning-comprehensive.mdc +159 -0
 - data/.cursor/rules/isolation_rules/Level3/task-tracking-intermediate.mdc +135 -0
 - data/.cursor/rules/isolation_rules/Phases/CreativePhase/creative-phase-architecture.mdc +187 -0
 - data/.cursor/rules/isolation_rules/main.mdc +123 -0
 - data/.cursor/rules/isolation_rules/visual-maps/archive-mode-map.mdc +277 -0
 - data/.cursor/rules/isolation_rules/visual-maps/creative-mode-map.mdc +224 -0
 - data/.cursor/rules/isolation_rules/visual-maps/implement-mode-map.mdc +321 -0
 - data/.cursor/rules/isolation_rules/visual-maps/plan-mode-map.mdc +269 -0
 - data/.cursor/rules/isolation_rules/visual-maps/qa-mode-map.mdc +495 -0
 - data/.cursor/rules/isolation_rules/visual-maps/reflect-mode-map.mdc +234 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van-mode-map.mdc +902 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-complexity-determination.mdc +60 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-file-verification.mdc +49 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-mode-map.mdc +49 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-platform-detection.mdc +50 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/build-test.mdc +117 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/config-check.mdc +103 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/dependency-check.mdc +147 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/environment-check.mdc +104 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-checks/file-verification.mdc +1 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-main.mdc +142 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/common-fixes.mdc +92 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/mode-transitions.mdc +101 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/reports.mdc +149 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/rule-calling-guide.mdc +66 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-utils/rule-calling-help.mdc +19 -0
 - data/.cursor/rules/isolation_rules/visual-maps/van_mode_split/van-qa-validation.md.old +363 -0
 - data/.env.example +7 -0
 - data/.memory_bank/activeContext.md +102 -0
 - data/.memory_bank/progress.md +93 -0
 - data/.memory_bank/projectbrief.md +45 -0
 - data/.memory_bank/systemPatterns.md +90 -0
 - data/.memory_bank/tasks.md +142 -0
 - data/.memory_bank/techContext.md +73 -0
 - data/.tool-versions +1 -0
 - data/CHANGELOG.md +42 -0
 - data/README.md +223 -5
 - data/examples/function_calling.rb +218 -0
 - data/examples/models_api.rb +125 -0
 - data/examples/safety_settings.rb +82 -0
 - data/lib/geminize/configuration.rb +4 -4
 - data/lib/geminize/model_info.rb +87 -8
 - data/lib/geminize/models/content_request_extensions.rb +219 -0
 - data/lib/geminize/models/content_request_safety.rb +123 -0
 - data/lib/geminize/models/content_response_extensions.rb +120 -0
 - data/lib/geminize/models/function_declaration.rb +112 -0
 - data/lib/geminize/models/function_response.rb +70 -0
 - data/lib/geminize/models/model.rb +101 -109
 - data/lib/geminize/models/model_list.rb +70 -28
 - data/lib/geminize/models/safety_setting.rb +102 -0
 - data/lib/geminize/models/tool.rb +47 -0
 - data/lib/geminize/models/tool_config.rb +52 -0
 - data/lib/geminize/module_extensions.rb +228 -0
 - data/lib/geminize/module_safety.rb +135 -0
 - data/lib/geminize/request_builder.rb +29 -0
 - data/lib/geminize/version.rb +1 -1
 - data/lib/geminize.rb +83 -14
 - metadata +57 -2
 
| 
         @@ -0,0 +1,219 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geminize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Extends ContentRequest with function calling and JSON mode support
         
     | 
| 
      
 6 
     | 
    
         
            +
                class ContentRequest
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # Additional attributes for function calling and JSON mode
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  # @return [Array<Geminize::Models::Tool>] The tools for this request
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attr_reader :tools
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # @return [Geminize::Models::ToolConfig, nil] The tool configuration
         
     | 
| 
      
 13 
     | 
    
         
            +
                  attr_reader :tool_config
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # @return [String, nil] The MIME type for the response format
         
     | 
| 
      
 16 
     | 
    
         
            +
                  attr_accessor :response_mime_type
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  # Add a function to the request
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # @param name [String] The name of the function
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # @param description [String] A description of what the function does
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @param parameters [Hash] JSON schema for function parameters
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the function is invalid
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def add_function(name, description, parameters)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @tools ||= []
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    function_declaration = FunctionDeclaration.new(name, description, parameters)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    tool = Tool.new(function_declaration)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    @tools << tool
         
     | 
| 
      
 31 
     | 
    
         
            +
                    self
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Set the tool config for function execution
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # @param execution_mode [String] The execution mode for functions ("AUTO", "MANUAL", or "NONE")
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the tool config is invalid
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def set_tool_config(execution_mode = "AUTO")
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @tool_config = ToolConfig.new(execution_mode)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    self
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # Enable JSON mode for structured output
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 45 
     | 
    
         
            +
                  def enable_json_mode
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @response_mime_type = "application/json"
         
     | 
| 
      
 47 
     | 
    
         
            +
                    self
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Disable JSON mode and return to regular text output
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def disable_json_mode
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @response_mime_type = nil
         
     | 
| 
      
 54 
     | 
    
         
            +
                    self
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # Override the to_hash method to include additional function calling features
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # @return [Hash] The request as a hash
         
     | 
| 
      
 59 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # First get the base implementation's hash by calling the standard method
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # Use the implementation from ContentRequest directly
         
     | 
| 
      
 62 
     | 
    
         
            +
                    request = {
         
     | 
| 
      
 63 
     | 
    
         
            +
                      contents: [
         
     | 
| 
      
 64 
     | 
    
         
            +
                        {
         
     | 
| 
      
 65 
     | 
    
         
            +
                          parts: @content_parts.map do |part|
         
     | 
| 
      
 66 
     | 
    
         
            +
                            if part[:type] == "text"
         
     | 
| 
      
 67 
     | 
    
         
            +
                              {text: part[:text]}
         
     | 
| 
      
 68 
     | 
    
         
            +
                            elsif part[:type] == "image"
         
     | 
| 
      
 69 
     | 
    
         
            +
                              {
         
     | 
| 
      
 70 
     | 
    
         
            +
                                inlineData: {
         
     | 
| 
      
 71 
     | 
    
         
            +
                                  mimeType: part[:mime_type],
         
     | 
| 
      
 72 
     | 
    
         
            +
                                  data: part[:data]
         
     | 
| 
      
 73 
     | 
    
         
            +
                                }
         
     | 
| 
      
 74 
     | 
    
         
            +
                              }
         
     | 
| 
      
 75 
     | 
    
         
            +
                            end
         
     | 
| 
      
 76 
     | 
    
         
            +
                          end.compact
         
     | 
| 
      
 77 
     | 
    
         
            +
                        }
         
     | 
| 
      
 78 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 79 
     | 
    
         
            +
                    }
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    # Add generation config
         
     | 
| 
      
 82 
     | 
    
         
            +
                    if @temperature || @max_tokens || @top_p || @top_k || @stop_sequences
         
     | 
| 
      
 83 
     | 
    
         
            +
                      request[:generationConfig] = {}
         
     | 
| 
      
 84 
     | 
    
         
            +
                      request[:generationConfig][:temperature] = @temperature if @temperature
         
     | 
| 
      
 85 
     | 
    
         
            +
                      request[:generationConfig][:maxOutputTokens] = @max_tokens if @max_tokens
         
     | 
| 
      
 86 
     | 
    
         
            +
                      request[:generationConfig][:topP] = @top_p if @top_p
         
     | 
| 
      
 87 
     | 
    
         
            +
                      request[:generationConfig][:topK] = @top_k if @top_k
         
     | 
| 
      
 88 
     | 
    
         
            +
                      request[:generationConfig][:stopSequences] = @stop_sequences if @stop_sequences
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    # Add system instruction
         
     | 
| 
      
 92 
     | 
    
         
            +
                    if @system_instruction
         
     | 
| 
      
 93 
     | 
    
         
            +
                      request[:systemInstruction] = {
         
     | 
| 
      
 94 
     | 
    
         
            +
                        parts: [
         
     | 
| 
      
 95 
     | 
    
         
            +
                          {
         
     | 
| 
      
 96 
     | 
    
         
            +
                            text: @system_instruction
         
     | 
| 
      
 97 
     | 
    
         
            +
                          }
         
     | 
| 
      
 98 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 99 
     | 
    
         
            +
                      }
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    # Add tools if present
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if @tools && !@tools.empty?
         
     | 
| 
      
 104 
     | 
    
         
            +
                      request[:tools] = @tools.map(&:to_hash)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    # Add tool config if present
         
     | 
| 
      
 108 
     | 
    
         
            +
                    if @tool_config
         
     | 
| 
      
 109 
     | 
    
         
            +
                      request[:toolConfig] = @tool_config.to_hash
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    # Add response format if JSON mode is enabled
         
     | 
| 
      
 113 
     | 
    
         
            +
                    if @response_mime_type
         
     | 
| 
      
 114 
     | 
    
         
            +
                      request[:generationConfig] ||= {}
         
     | 
| 
      
 115 
     | 
    
         
            +
                      request[:generationConfig][:responseSchema] = {
         
     | 
| 
      
 116 
     | 
    
         
            +
                        type: "object",
         
     | 
| 
      
 117 
     | 
    
         
            +
                        properties: {
         
     | 
| 
      
 118 
     | 
    
         
            +
                          # Add a sample property to satisfy the API requirement
         
     | 
| 
      
 119 
     | 
    
         
            +
                          # This is a generic structure that will be overridden by the model's understanding
         
     | 
| 
      
 120 
     | 
    
         
            +
                          # of what properties to include based on the prompt
         
     | 
| 
      
 121 
     | 
    
         
            +
                          result: {
         
     | 
| 
      
 122 
     | 
    
         
            +
                            type: "array",
         
     | 
| 
      
 123 
     | 
    
         
            +
                            items: {
         
     | 
| 
      
 124 
     | 
    
         
            +
                              type: "object",
         
     | 
| 
      
 125 
     | 
    
         
            +
                              properties: {
         
     | 
| 
      
 126 
     | 
    
         
            +
                                name: {type: "string"},
         
     | 
| 
      
 127 
     | 
    
         
            +
                                value: {type: "string"}
         
     | 
| 
      
 128 
     | 
    
         
            +
                              }
         
     | 
| 
      
 129 
     | 
    
         
            +
                            }
         
     | 
| 
      
 130 
     | 
    
         
            +
                          }
         
     | 
| 
      
 131 
     | 
    
         
            +
                        }
         
     | 
| 
      
 132 
     | 
    
         
            +
                      }
         
     | 
| 
      
 133 
     | 
    
         
            +
                      request[:generationConfig][:responseMimeType] = @response_mime_type
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                    request
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  # Original validate! method includes validation for tools and JSON mode
         
     | 
| 
      
 140 
     | 
    
         
            +
                  alias_method :original_validate!, :validate!
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  def validate!
         
     | 
| 
      
 143 
     | 
    
         
            +
                    # Don't call super, instead call the original specific validations directly
         
     | 
| 
      
 144 
     | 
    
         
            +
                    validate_prompt!
         
     | 
| 
      
 145 
     | 
    
         
            +
                    validate_system_instruction! if @system_instruction
         
     | 
| 
      
 146 
     | 
    
         
            +
                    validate_temperature! if @temperature
         
     | 
| 
      
 147 
     | 
    
         
            +
                    validate_max_tokens! if @max_tokens
         
     | 
| 
      
 148 
     | 
    
         
            +
                    validate_top_p! if @top_p
         
     | 
| 
      
 149 
     | 
    
         
            +
                    validate_top_k! if @top_k
         
     | 
| 
      
 150 
     | 
    
         
            +
                    validate_stop_sequences! if @stop_sequences
         
     | 
| 
      
 151 
     | 
    
         
            +
                    validate_content_parts!
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                    # Then validate our extensions
         
     | 
| 
      
 154 
     | 
    
         
            +
                    validate_tools!
         
     | 
| 
      
 155 
     | 
    
         
            +
                    validate_tool_config!
         
     | 
| 
      
 156 
     | 
    
         
            +
                    validate_response_mime_type!
         
     | 
| 
      
 157 
     | 
    
         
            +
                    true
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                  private
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                  # Validate the tools
         
     | 
| 
      
 163 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the tools are invalid
         
     | 
| 
      
 164 
     | 
    
         
            +
                  def validate_tools!
         
     | 
| 
      
 165 
     | 
    
         
            +
                    return if @tools.nil? || @tools.empty?
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                    unless @tools.is_a?(Array)
         
     | 
| 
      
 168 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 169 
     | 
    
         
            +
                        "Tools must be an array, got #{@tools.class}",
         
     | 
| 
      
 170 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 171 
     | 
    
         
            +
                      )
         
     | 
| 
      
 172 
     | 
    
         
            +
                    end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                    @tools.each_with_index do |tool, index|
         
     | 
| 
      
 175 
     | 
    
         
            +
                      unless tool.is_a?(Tool)
         
     | 
| 
      
 176 
     | 
    
         
            +
                        raise Geminize::ValidationError.new(
         
     | 
| 
      
 177 
     | 
    
         
            +
                          "Tool at index #{index} must be a Tool, got #{tool.class}",
         
     | 
| 
      
 178 
     | 
    
         
            +
                          "INVALID_ARGUMENT"
         
     | 
| 
      
 179 
     | 
    
         
            +
                        )
         
     | 
| 
      
 180 
     | 
    
         
            +
                      end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                  # Validate the tool config
         
     | 
| 
      
 185 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the tool config is invalid
         
     | 
| 
      
 186 
     | 
    
         
            +
                  def validate_tool_config!
         
     | 
| 
      
 187 
     | 
    
         
            +
                    return if @tool_config.nil?
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                    unless @tool_config.is_a?(ToolConfig)
         
     | 
| 
      
 190 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 191 
     | 
    
         
            +
                        "Tool config must be a ToolConfig, got #{@tool_config.class}",
         
     | 
| 
      
 192 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 193 
     | 
    
         
            +
                      )
         
     | 
| 
      
 194 
     | 
    
         
            +
                    end
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  # Validate the response MIME type
         
     | 
| 
      
 198 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the response MIME type is invalid
         
     | 
| 
      
 199 
     | 
    
         
            +
                  def validate_response_mime_type!
         
     | 
| 
      
 200 
     | 
    
         
            +
                    return if @response_mime_type.nil?
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    unless @response_mime_type.is_a?(String)
         
     | 
| 
      
 203 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 204 
     | 
    
         
            +
                        "Response MIME type must be a string, got #{@response_mime_type.class}",
         
     | 
| 
      
 205 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 206 
     | 
    
         
            +
                      )
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                    # For now, only allow JSON
         
     | 
| 
      
 210 
     | 
    
         
            +
                    unless @response_mime_type == "application/json"
         
     | 
| 
      
 211 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 212 
     | 
    
         
            +
                        "Response MIME type must be 'application/json', got #{@response_mime_type}",
         
     | 
| 
      
 213 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 214 
     | 
    
         
            +
                      )
         
     | 
| 
      
 215 
     | 
    
         
            +
                    end
         
     | 
| 
      
 216 
     | 
    
         
            +
                  end
         
     | 
| 
      
 217 
     | 
    
         
            +
                end
         
     | 
| 
      
 218 
     | 
    
         
            +
              end
         
     | 
| 
      
 219 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,123 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geminize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Extends ContentRequest with safety settings support
         
     | 
| 
      
 6 
     | 
    
         
            +
                class ContentRequest
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # @return [Array<Geminize::Models::SafetySetting>] The safety settings for this request
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :safety_settings
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # Add a safety setting to the request
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @param category [String] The harm category this setting applies to
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # @param threshold [String] The threshold level for filtering
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the safety setting is invalid
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def add_safety_setting(category, threshold)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @safety_settings ||= []
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    safety_setting = SafetySetting.new(category, threshold)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @safety_settings << safety_setting
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    self
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # Set default safety settings for all harm categories
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # @param threshold [String] The threshold level to apply to all categories
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the threshold is invalid
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def set_default_safety_settings(threshold)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @safety_settings = []
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    SafetySetting::HARM_CATEGORIES.each do |category|
         
     | 
| 
      
 32 
     | 
    
         
            +
                      add_safety_setting(category, threshold)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    self
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # Block all harmful content (most conservative setting)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def block_all_harmful_content
         
     | 
| 
      
 41 
     | 
    
         
            +
                    set_default_safety_settings("BLOCK_LOW_AND_ABOVE")
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  # Block only high-risk content (least conservative setting)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 46 
     | 
    
         
            +
                  def block_only_high_risk_content
         
     | 
| 
      
 47 
     | 
    
         
            +
                    set_default_safety_settings("BLOCK_ONLY_HIGH")
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Remove all safety settings (use with caution)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # @return [self] The request object for chaining
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def remove_safety_settings
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @safety_settings = []
         
     | 
| 
      
 54 
     | 
    
         
            +
                    self
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # Get the base to_hash method - this will use the one defined in content_request_extensions.rb if available
         
     | 
| 
      
 58 
     | 
    
         
            +
                  alias_method :safety_original_to_hash, :to_hash unless method_defined?(:safety_original_to_hash)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  # Override the to_hash method to include safety settings
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # @return [Hash] The request as a hash
         
     | 
| 
      
 62 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # Get the base hash (will include tools if that extension is loaded)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    request = defined?(original_to_hash) ? original_to_hash : safety_original_to_hash
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    # Add safety settings if present
         
     | 
| 
      
 67 
     | 
    
         
            +
                    if @safety_settings && !@safety_settings.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                      request[:safetySettings] = @safety_settings.map(&:to_hash)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    request
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  # Validate method for safety settings - should only be called if not overridden by content_request_extensions.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # If that file's validate! is called, it should also call validate_safety_settings!
         
     | 
| 
      
 76 
     | 
    
         
            +
                  def validate!
         
     | 
| 
      
 77 
     | 
    
         
            +
                    # Don't call super, instead call the necessary validations directly
         
     | 
| 
      
 78 
     | 
    
         
            +
                    # Check if original_validate! is defined from the extensions
         
     | 
| 
      
 79 
     | 
    
         
            +
                    if defined?(original_validate!)
         
     | 
| 
      
 80 
     | 
    
         
            +
                      original_validate!
         
     | 
| 
      
 81 
     | 
    
         
            +
                    else
         
     | 
| 
      
 82 
     | 
    
         
            +
                      # Call the original internal validation methods
         
     | 
| 
      
 83 
     | 
    
         
            +
                      validate_prompt!
         
     | 
| 
      
 84 
     | 
    
         
            +
                      validate_system_instruction! if @system_instruction
         
     | 
| 
      
 85 
     | 
    
         
            +
                      validate_temperature! if @temperature
         
     | 
| 
      
 86 
     | 
    
         
            +
                      validate_max_tokens! if @max_tokens
         
     | 
| 
      
 87 
     | 
    
         
            +
                      validate_top_p! if @top_p
         
     | 
| 
      
 88 
     | 
    
         
            +
                      validate_top_k! if @top_k
         
     | 
| 
      
 89 
     | 
    
         
            +
                      validate_stop_sequences! if @stop_sequences
         
     | 
| 
      
 90 
     | 
    
         
            +
                      validate_content_parts!
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    # Add our safety validation
         
     | 
| 
      
 94 
     | 
    
         
            +
                    validate_safety_settings!
         
     | 
| 
      
 95 
     | 
    
         
            +
                    true
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  private
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  # Validate the safety settings
         
     | 
| 
      
 101 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the safety settings are invalid
         
     | 
| 
      
 102 
     | 
    
         
            +
                  def validate_safety_settings!
         
     | 
| 
      
 103 
     | 
    
         
            +
                    return if @safety_settings.nil? || @safety_settings.empty?
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    unless @safety_settings.is_a?(Array)
         
     | 
| 
      
 106 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 107 
     | 
    
         
            +
                        "Safety settings must be an array, got #{@safety_settings.class}",
         
     | 
| 
      
 108 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 109 
     | 
    
         
            +
                      )
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    @safety_settings.each_with_index do |setting, index|
         
     | 
| 
      
 113 
     | 
    
         
            +
                      unless setting.is_a?(SafetySetting)
         
     | 
| 
      
 114 
     | 
    
         
            +
                        raise Geminize::ValidationError.new(
         
     | 
| 
      
 115 
     | 
    
         
            +
                          "Safety setting at index #{index} must be a SafetySetting, got #{setting.class}",
         
     | 
| 
      
 116 
     | 
    
         
            +
                          "INVALID_ARGUMENT"
         
     | 
| 
      
 117 
     | 
    
         
            +
                        )
         
     | 
| 
      
 118 
     | 
    
         
            +
                      end
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
              end
         
     | 
| 
      
 123 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,120 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geminize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Extends ContentResponse with function calling response handling
         
     | 
| 
      
 6 
     | 
    
         
            +
                class ContentResponse
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # Get the function call information from the response
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @return [Geminize::Models::FunctionResponse, nil] Function call information or nil if not present
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def function_call
         
     | 
| 
      
 10 
     | 
    
         
            +
                    return @function_call if defined?(@function_call)
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    @function_call = nil
         
     | 
| 
      
 13 
     | 
    
         
            +
                    candidates = @raw_response["candidates"]
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    if candidates && !candidates.empty?
         
     | 
| 
      
 16 
     | 
    
         
            +
                      content = candidates.first["content"]
         
     | 
| 
      
 17 
     | 
    
         
            +
                      if content && content["parts"] && !content["parts"].empty?
         
     | 
| 
      
 18 
     | 
    
         
            +
                        function_call_part = content["parts"].find { |part| part["functionCall"] || part["function_call"] }
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                        if function_call_part
         
     | 
| 
      
 21 
     | 
    
         
            +
                          # Handle both "functionCall" and "function_call" formats (API may vary)
         
     | 
| 
      
 22 
     | 
    
         
            +
                          function_data = function_call_part["functionCall"] || function_call_part["function_call"]
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                          if function_data
         
     | 
| 
      
 25 
     | 
    
         
            +
                            # Extract name and args - handle different API response formats
         
     | 
| 
      
 26 
     | 
    
         
            +
                            name = function_data["name"]
         
     | 
| 
      
 27 
     | 
    
         
            +
                            args = function_data["args"] || function_data["arguments"]
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                            if name
         
     | 
| 
      
 30 
     | 
    
         
            +
                              @function_call = FunctionResponse.new(name, args || {})
         
     | 
| 
      
 31 
     | 
    
         
            +
                            end
         
     | 
| 
      
 32 
     | 
    
         
            +
                          end
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    @function_call
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  # Check if the response contains a function call
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # @return [Boolean] True if the response contains a function call
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def has_function_call?
         
     | 
| 
      
 43 
     | 
    
         
            +
                    !function_call.nil?
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  # Get structured JSON response if available
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @return [Hash, nil] Parsed JSON response or nil if not a JSON response
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def json_response
         
     | 
| 
      
 49 
     | 
    
         
            +
                    return @json_response if defined?(@json_response)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    @json_response = nil
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    if has_text?
         
     | 
| 
      
 54 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 55 
     | 
    
         
            +
                        @json_response = JSON.parse(text)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      rescue JSON::ParserError
         
     | 
| 
      
 57 
     | 
    
         
            +
                        # Try to parse any JSON-like content from the text
         
     | 
| 
      
 58 
     | 
    
         
            +
                        json_match = text.match(/```json\s*(.*?)\s*```/m) || text.match(/\{.*\}/m) || text.match(/\[.*\]/m)
         
     | 
| 
      
 59 
     | 
    
         
            +
                        if json_match
         
     | 
| 
      
 60 
     | 
    
         
            +
                          begin
         
     | 
| 
      
 61 
     | 
    
         
            +
                            @json_response = JSON.parse(json_match[1] || json_match[0])
         
     | 
| 
      
 62 
     | 
    
         
            +
                          rescue JSON::ParserError
         
     | 
| 
      
 63 
     | 
    
         
            +
                            # Still not valid JSON
         
     | 
| 
      
 64 
     | 
    
         
            +
                            @json_response = nil
         
     | 
| 
      
 65 
     | 
    
         
            +
                          end
         
     | 
| 
      
 66 
     | 
    
         
            +
                        end
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    @json_response
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # Check if the response contains valid JSON
         
     | 
| 
      
 74 
     | 
    
         
            +
                  # @return [Boolean] True if the response contains valid JSON
         
     | 
| 
      
 75 
     | 
    
         
            +
                  def has_json_response?
         
     | 
| 
      
 76 
     | 
    
         
            +
                    !json_response.nil?
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  # Enhanced parse_response method to handle function calls
         
     | 
| 
      
 80 
     | 
    
         
            +
                  alias_method :original_parse_response, :parse_response
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  private
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  # Parse the response data and extract relevant information
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def parse_response
         
     | 
| 
      
 86 
     | 
    
         
            +
                    original_parse_response
         
     | 
| 
      
 87 
     | 
    
         
            +
                    # Clear any cached function call before parsing again
         
     | 
| 
      
 88 
     | 
    
         
            +
                    remove_instance_variable(:@function_call) if defined?(@function_call)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    parse_function_call
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  # Parse function call information from the response
         
     | 
| 
      
 93 
     | 
    
         
            +
                  def parse_function_call
         
     | 
| 
      
 94 
     | 
    
         
            +
                    candidates = @raw_response["candidates"]
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    if candidates && !candidates.empty?
         
     | 
| 
      
 97 
     | 
    
         
            +
                      content = candidates.first["content"]
         
     | 
| 
      
 98 
     | 
    
         
            +
                      if content && content["parts"] && !content["parts"].empty?
         
     | 
| 
      
 99 
     | 
    
         
            +
                        function_call_part = content["parts"].find { |part| part["functionCall"] || part["function_call"] }
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                        if function_call_part
         
     | 
| 
      
 102 
     | 
    
         
            +
                          # Handle both "functionCall" and "function_call" formats (API may vary)
         
     | 
| 
      
 103 
     | 
    
         
            +
                          function_data = function_call_part["functionCall"] || function_call_part["function_call"]
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                          if function_data
         
     | 
| 
      
 106 
     | 
    
         
            +
                            # Extract name and args - handle different API response formats
         
     | 
| 
      
 107 
     | 
    
         
            +
                            name = function_data["name"]
         
     | 
| 
      
 108 
     | 
    
         
            +
                            args = function_data["args"] || function_data["arguments"]
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                            if name
         
     | 
| 
      
 111 
     | 
    
         
            +
                              @function_call = FunctionResponse.new(name, args || {})
         
     | 
| 
      
 112 
     | 
    
         
            +
                            end
         
     | 
| 
      
 113 
     | 
    
         
            +
                          end
         
     | 
| 
      
 114 
     | 
    
         
            +
                        end
         
     | 
| 
      
 115 
     | 
    
         
            +
                      end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    end
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geminize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Represents a function declaration for function calling in Gemini API
         
     | 
| 
      
 6 
     | 
    
         
            +
                class FunctionDeclaration
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # @return [String] Name of the function
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :name
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # @return [String] Description of what the function does
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :description
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # @return [Hash] JSON schema for function parameters
         
     | 
| 
      
 14 
     | 
    
         
            +
                  attr_reader :parameters
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # Initialize a new function declaration
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # @param name [String] The name of the function
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @param description [String] A description of what the function does
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # @param parameters [Hash] JSON schema for function parameters
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the function declaration is invalid
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def initialize(name, description, parameters)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @name = name
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @description = description
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @parameters = parameters
         
     | 
| 
      
 25 
     | 
    
         
            +
                    validate!
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Validate the function declaration
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the function declaration is invalid
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # @return [Boolean] true if validation passes
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def validate!
         
     | 
| 
      
 32 
     | 
    
         
            +
                    validate_name!
         
     | 
| 
      
 33 
     | 
    
         
            +
                    validate_description!
         
     | 
| 
      
 34 
     | 
    
         
            +
                    validate_parameters!
         
     | 
| 
      
 35 
     | 
    
         
            +
                    true
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # Convert the function declaration to a hash for API requests
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # @return [Hash] The function declaration as a hash
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 41 
     | 
    
         
            +
                    {
         
     | 
| 
      
 42 
     | 
    
         
            +
                      name: @name,
         
     | 
| 
      
 43 
     | 
    
         
            +
                      description: @description,
         
     | 
| 
      
 44 
     | 
    
         
            +
                      parameters: @parameters
         
     | 
| 
      
 45 
     | 
    
         
            +
                    }
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  # Alias for to_hash
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # @return [Hash] The function declaration as a hash
         
     | 
| 
      
 50 
     | 
    
         
            +
                  def to_h
         
     | 
| 
      
 51 
     | 
    
         
            +
                    to_hash
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  private
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  # Validate the function name
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the name is invalid
         
     | 
| 
      
 58 
     | 
    
         
            +
                  def validate_name!
         
     | 
| 
      
 59 
     | 
    
         
            +
                    unless @name.is_a?(String)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 61 
     | 
    
         
            +
                        "Function name must be a string, got #{@name.class}",
         
     | 
| 
      
 62 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 63 
     | 
    
         
            +
                      )
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    if @name.empty?
         
     | 
| 
      
 67 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 68 
     | 
    
         
            +
                        "Function name cannot be empty",
         
     | 
| 
      
 69 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 70 
     | 
    
         
            +
                      )
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  # Validate the function description
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the description is invalid
         
     | 
| 
      
 76 
     | 
    
         
            +
                  def validate_description!
         
     | 
| 
      
 77 
     | 
    
         
            +
                    unless @description.is_a?(String)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 79 
     | 
    
         
            +
                        "Function description must be a string, got #{@description.class}",
         
     | 
| 
      
 80 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 81 
     | 
    
         
            +
                      )
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    if @description.empty?
         
     | 
| 
      
 85 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 86 
     | 
    
         
            +
                        "Function description cannot be empty",
         
     | 
| 
      
 87 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 88 
     | 
    
         
            +
                      )
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  # Validate the function parameters
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the parameters are invalid
         
     | 
| 
      
 94 
     | 
    
         
            +
                  def validate_parameters!
         
     | 
| 
      
 95 
     | 
    
         
            +
                    unless @parameters.is_a?(Hash)
         
     | 
| 
      
 96 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 97 
     | 
    
         
            +
                        "Function parameters must be a hash, got #{@parameters.class}",
         
     | 
| 
      
 98 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 99 
     | 
    
         
            +
                      )
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    # Validate that the parameters follow JSON Schema format
         
     | 
| 
      
 103 
     | 
    
         
            +
                    unless @parameters.key?(:type) || @parameters.key?("type")
         
     | 
| 
      
 104 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 105 
     | 
    
         
            +
                        "Function parameters must include a 'type' field",
         
     | 
| 
      
 106 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 107 
     | 
    
         
            +
                      )
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Geminize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Represents a function response from Gemini API
         
     | 
| 
      
 6 
     | 
    
         
            +
                class FunctionResponse
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # @return [String] The name of the function that was called
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :name
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # @return [Hash, Array, String, Numeric, Boolean, nil] The response from the function
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :response
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # Initialize a new function response
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @param name [String] The name of the function that was called
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @param response [Hash, Array, String, Numeric, Boolean, nil] The response from the function
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def initialize(name, response)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @name = name
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @response = response
         
     | 
| 
      
 19 
     | 
    
         
            +
                    validate!
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # Validate the function response
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the function response is invalid
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # @return [Boolean] true if validation passes
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def validate!
         
     | 
| 
      
 26 
     | 
    
         
            +
                    if @name.nil? || @name.empty?
         
     | 
| 
      
 27 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 28 
     | 
    
         
            +
                        "Function name cannot be empty",
         
     | 
| 
      
 29 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 30 
     | 
    
         
            +
                      )
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    true
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  # Create a FunctionResponse from a hash
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # @param hash [Hash] The hash representation of a function response
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # @return [Geminize::Models::FunctionResponse] The function response
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # @raise [Geminize::ValidationError] If the hash is invalid
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def self.from_hash(hash)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    unless hash.is_a?(Hash)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      raise Geminize::ValidationError.new(
         
     | 
| 
      
 43 
     | 
    
         
            +
                        "Expected a Hash, got #{hash.class}",
         
     | 
| 
      
 44 
     | 
    
         
            +
                        "INVALID_ARGUMENT"
         
     | 
| 
      
 45 
     | 
    
         
            +
                      )
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    name = hash["name"] || hash[:name]
         
     | 
| 
      
 49 
     | 
    
         
            +
                    response = hash["response"] || hash[:response]
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    new(name, response)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # Convert the function response to a hash
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # @return [Hash] The function response as a hash
         
     | 
| 
      
 56 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 57 
     | 
    
         
            +
                    {
         
     | 
| 
      
 58 
     | 
    
         
            +
                      name: @name,
         
     | 
| 
      
 59 
     | 
    
         
            +
                      response: @response
         
     | 
| 
      
 60 
     | 
    
         
            +
                    }
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  # Alias for to_hash
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # @return [Hash] The function response as a hash
         
     | 
| 
      
 65 
     | 
    
         
            +
                  def to_h
         
     | 
| 
      
 66 
     | 
    
         
            +
                    to_hash
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     |