class ActiveGenie::Clients::GoogleClient

def function_calling(messages, function, model_tier: nil, config: {})

Returns:
  • (Hash, nil) - The parsed JSON object matching the schema, or nil if parsing fails or content is empty.

Parameters:
  • config (Hash) -- Optional configuration overrides:
  • model_tier (Symbol, nil) -- A symbolic representation of the model quality/size tier.
  • function (Hash) -- A JSON schema definition describing the desired output format.
  • messages (Array) -- A list of messages representing the conversation history.
def function_calling(messages, function, model_tier: nil, config: {})
  model = config[:runtime][:model] || @app_config.tier_to_model(model_tier)
  api_key = config[:runtime][:api_key] || @app_config.api_key
  contents = convert_messages_to_contents(messages, function)
  contents << output_as_json_schema(function)
  payload = {
    contents: contents,
    generationConfig: {
      response_mime_type: "application/json",
      temperature: 0.1
    }
  }
  endpoint = "#{API_VERSION_PATH}/#{model}:generateContent"
  params = { key: api_key }
  headers = DEFAULT_HEADERS
  retry_with_backoff(config:) do
    start_time = Time.now
    
    response = post(endpoint, payload, headers:, params:, config: config)
    
    json_string = response&.dig('candidates', 0, 'content', 'parts', 0, 'text')
    return nil if json_string.nil? || json_string.empty?
    begin
      parsed_response = JSON.parse(json_string)
      
      # Log usage metrics
      usage_metadata = response['usageMetadata'] || {}
      prompt_tokens = usage_metadata['promptTokenCount'] || 0
      candidates_tokens = usage_metadata['candidatesTokenCount'] || 0
      total_tokens = usage_metadata['totalTokenCount'] || (prompt_tokens + candidates_tokens)
      ActiveGenie::Logger.trace({
        code: :llm_usage,
        input_tokens: prompt_tokens,
        output_tokens: candidates_tokens,
        total_tokens: total_tokens,
        model: model,
        duration: Time.now - start_time,
        usage: usage_metadata
      })
      
      ActiveGenie::Logger.trace({ code: :function_calling, payload:, parsed_response: })
      
      normalize_function_output(parsed_response)
    rescue JSON::ParserError => e
      raise GoogleError, "Failed to parse Google API response: #{e.message} - Content: #{json_string}"
    end
  end
end