rasti-ai 1.2.0 → 1.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f62b3decd7ee67906392eff6218e29fd8a66bee1f5dc41729e4412193f7ff4d0
4
- data.tar.gz: 3368912d5ee86e2ba10408aa4795c97820b8f313a6d17d693deca2f0454ad9e8
3
+ metadata.gz: 6e8aa13644a19b41a31445f268339fb14a9521ce85538493768bc5ee985b2a40
4
+ data.tar.gz: 82bc0cf208f412df7958bb8b95f5bdfa2b5deec0b892834afe82d0675543179e
5
5
  SHA512:
6
- metadata.gz: da0b274e1ed8e4d4c0d9d4f7867ca546f47bc13c48246e111a71f465719237abf11985384699097f19d61822a33575fdd2a3398c63b2bb12a4612b11e563cec6
7
- data.tar.gz: 48618afd26f383ff8c38d7527c3aac4f44015c9812677c93a893c7d9ccbddc0ed8cd4f6ebb6309acac3c334effaffec6138fb72715f036a51083839129f44cab
6
+ metadata.gz: 93490666739ff2b3dbc01a023149b947ee88e8ba503224194f968892b0070595bdc463332a22be3a0d77dbdae6ced218dbe62f6589fddb590def2ccc6a7e6fd2
7
+ data.tar.gz: 0c0ca23c2a085fdba7549ffa0696c8ffe8e492a626b5c123bf7259310a4088f6177acab70e14c7b856f8cb6d2a0743c5722fa18edc1e7f9bd7c84e1d4b2b45cd
@@ -5,12 +5,17 @@ module Rasti
5
5
 
6
6
  BASE_URL = 'https://api.openai.com/v1'.freeze
7
7
 
8
- def initialize(api_key:nil, logger:nil)
8
+ RETRYABLE_STATUS_CODES = [502, 503, 504].freeze
9
+
10
+ def initialize(api_key:nil, logger:nil, http_connect_timeout:nil, http_read_timeout:nil, http_max_retries:nil)
9
11
  @api_key = api_key || Rasti::AI.openai_api_key
10
12
  @logger = logger || Rasti::AI.logger
13
+ @http_connect_timeout = http_connect_timeout || Rasti::AI.http_connect_timeout
14
+ @http_read_timeout = http_read_timeout || Rasti::AI.http_read_timeout
15
+ @http_max_retries = http_max_retries || Rasti::AI.http_max_retries
11
16
  end
12
17
 
13
- def chat_completions(messages:, model:nil, tools:[], response_format: nil)
18
+ def chat_completions(messages:, model:nil, tools:[], response_format:nil)
14
19
  body = {
15
20
  model: model || Rasti::AI.openai_default_model,
16
21
  messages: messages,
@@ -25,35 +30,54 @@ module Rasti
25
30
 
26
31
  private
27
32
 
28
- attr_reader :api_key, :logger
33
+ attr_reader :api_key, :logger, :http_connect_timeout, :http_read_timeout, :http_max_retries
29
34
 
30
35
  def post(relative_url, body)
31
- url = "#{BASE_URL}#{relative_url}"
32
- uri = URI(url)
36
+ max_retries = http_max_retries
37
+ retry_count = 0
38
+
39
+ begin
40
+ url = "#{BASE_URL}#{relative_url}"
41
+ uri = URI.parse url
42
+
43
+ logger.info(self.class) { "POST #{url}" }
44
+ logger.debug(self.class) { JSON.pretty_generate(body) }
45
+
46
+ request = Net::HTTP::Post.new uri
47
+ request['Authorization'] = "Bearer #{api_key}"
48
+ request['Content-Type'] = 'application/json'
49
+ request.body = JSON.dump body
33
50
 
34
- logger.info(self.class) { "POST #{url}" }
35
- logger.debug(self.class) { JSON.pretty_generate(body) }
51
+ http = Net::HTTP.new uri.host, uri.port
52
+ http.use_ssl = (uri.scheme == 'https')
36
53
 
37
- request = Net::HTTP::Post.new uri
38
- request['Authorization'] = "Bearer #{api_key}"
39
- request['Content-Type'] = 'application/json'
40
- request.body = JSON.dump(body)
54
+ http.open_timeout = http_connect_timeout
55
+ http.read_timeout = http_read_timeout
41
56
 
42
- http = Net::HTTP.new uri.host, uri.port
43
- http.use_ssl = uri.scheme == 'https'
57
+ response = http.request request
44
58
 
45
- response = http.request request
59
+ logger.info(self.class) { "Response #{response.code}" }
60
+ logger.debug(self.class) { response.body }
46
61
 
47
- logger.info(self.class) { "Response #{response.code}" }
48
- logger.debug(self.class) { response.body }
62
+ if !response.is_a?(Net::HTTPSuccess) || RETRYABLE_STATUS_CODES.include?(response.code.to_i)
63
+ raise Errors::RequestFail.new(url, body, response)
64
+ end
49
65
 
50
- raise Errors::RequestFail.new(url, body, response) unless response.is_a? Net::HTTPSuccess
66
+ JSON.parse response.body
51
67
 
52
- JSON.parse response.body
68
+ rescue SocketError, Net::OpenTimeout, Net::ReadTimeout, Errors::RequestFail => e
69
+ if retry_count < max_retries
70
+ retry_count += 1
71
+ logger.warn(self.class) { "#{e.class.name}: #{e.message} (#{retry_count}/#{max_retries})" }
72
+ sleep retry_count
73
+ retry
74
+ end
75
+ raise
76
+ end
53
77
  end
54
78
 
55
79
  end
56
80
  end
57
81
 
58
82
  end
59
- end
83
+ end
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module AI
3
- VERSION = '1.2.0'
3
+ VERSION = '1.2.1'
4
4
  end
5
5
  end
data/lib/rasti/ai.rb CHANGED
@@ -17,6 +17,10 @@ module Rasti
17
17
 
18
18
  attr_config :logger, Logger.new(STDOUT)
19
19
 
20
+ attr_config :http_connect_timeout, 60
21
+ attr_config :http_read_timeout, 60
22
+ attr_config :http_max_retries, 3
23
+
20
24
  attr_config :openai_api_key, ENV['OPENAI_API_KEY']
21
25
  attr_config :openai_default_model, ENV['OPENAI_DEFAULT_MODEL']
22
26
 
@@ -15,6 +15,8 @@ require_relative 'support/helpers/resources'
15
15
  Rasti::AI.configure do |config|
16
16
  config.logger.level = Logger::FATAL
17
17
 
18
+ config.http_max_retries = 1
19
+
18
20
  config.openai_api_key = 'test_api_key'
19
21
  config.openai_default_model = 'gpt-test'
20
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasti-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-18 00:00:00.000000000 Z
11
+ date: 2025-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_require