rager 0.5.0 → 0.7.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/README.md +49 -7
- data/lib/rager/chat/message.rb +10 -0
- data/lib/rager/chat/message_content.rb +7 -0
- data/lib/rager/chat/message_delta.rb +7 -0
- data/lib/rager/chat/options.rb +12 -9
- data/lib/rager/chat/providers/openai.rb +64 -48
- data/lib/rager/chat/schema.rb +3 -4
- data/lib/rager/config.rb +16 -20
- data/lib/rager/context.rb +326 -97
- data/lib/rager/context_options.rb +23 -0
- data/lib/rager/embed/options.rb +4 -3
- data/lib/rager/embed/providers/openai.rb +14 -6
- data/lib/rager/errors/credentials_error.rb +24 -0
- data/lib/rager/errors/dependency_error.rb +23 -0
- data/lib/rager/errors/http_error.rb +12 -5
- data/lib/rager/errors/options_error.rb +10 -5
- data/lib/rager/errors/parse_error.rb +9 -5
- data/lib/rager/errors/template_error.rb +10 -4
- data/lib/rager/errors/timeout_error.rb +25 -0
- data/lib/rager/http/adapters/async_http.rb +66 -14
- data/lib/rager/http/adapters/mock.rb +41 -45
- data/lib/rager/http/adapters/net_http.rb +144 -0
- data/lib/rager/http/request.rb +2 -0
- data/lib/rager/{image_gen → image}/options.rb +5 -4
- data/lib/rager/{image_gen → image}/output_format.rb +1 -1
- data/lib/rager/{image_gen → image}/providers/abstract.rb +4 -4
- data/lib/rager/{image_gen → image}/providers/replicate.rb +19 -14
- data/lib/rager/{logger.rb → log_strategy.rb} +2 -1
- data/lib/rager/{mesh_gen → mesh}/options.rb +4 -3
- data/lib/rager/{mesh_gen → mesh}/providers/abstract.rb +4 -4
- data/lib/rager/{mesh_gen → mesh}/providers/replicate.rb +20 -14
- data/lib/rager/operation.rb +2 -2
- data/lib/rager/options.rb +1 -1
- data/lib/rager/outcome.rb +25 -0
- data/lib/rager/providers.rb +61 -0
- data/lib/rager/rerank/{query.rb → input.rb} +8 -1
- data/lib/rager/rerank/options.rb +3 -2
- data/lib/rager/rerank/providers/abstract.rb +2 -2
- data/lib/rager/rerank/providers/cohere.rb +24 -15
- data/lib/rager/rerank/result.rb +8 -1
- data/lib/rager/result.rb +98 -108
- data/lib/rager/search/options.rb +4 -1
- data/lib/rager/search/providers/jina.rb +68 -0
- data/lib/rager/search/result.rb +9 -2
- data/lib/rager/template/input.rb +9 -0
- data/lib/rager/template/options.rb +1 -1
- data/lib/rager/template/providers/erb.rb +3 -3
- data/lib/rager/template/providers/mustache.rb +30 -0
- data/lib/rager/types.rb +28 -17
- data/lib/rager/utils/http.rb +92 -27
- data/lib/rager/utils/replicate.rb +40 -21
- data/lib/rager/utils/runtime.rb +21 -0
- data/lib/rager/version.rb +1 -1
- metadata +22 -36
- data/lib/rager/chat.rb +0 -35
- data/lib/rager/embed.rb +0 -35
- data/lib/rager/errors/missing_credentials_error.rb +0 -19
- data/lib/rager/errors/unknown_provider_error.rb +0 -17
- data/lib/rager/image_gen.rb +0 -31
- data/lib/rager/mesh_gen.rb +0 -31
- data/lib/rager/rerank.rb +0 -35
- data/lib/rager/search/providers/brave.rb +0 -59
- data/lib/rager/search.rb +0 -35
- data/lib/rager/template.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a240f204b0677aee45009f9357cea5e13b85eaa77dd9696db6e12e065f0144b4
|
4
|
+
data.tar.gz: 8d31692e3d8fe5d962ff4f2a9a94817a8886dd20f01eb72cbb24189deb490365
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 381d1ee7c8202be21536d209d3845039223709e7dd4e93c974f1970ce4b019f8538cac0bcb6cae7c8c15209e86bde9d6adb0e10d9e9b4546734744d4be7133dd
|
7
|
+
data.tar.gz: 34341e107e1018810723d9bdbd5f6e0b6fc69f66daf166860aec9f4513b29827479754ba84afe07cf5e9ece45cacf23c0e34f70f8fe896fd14c2b99d86a9f878
|
data/README.md
CHANGED
@@ -4,23 +4,65 @@
|
|
4
4
|
[](https://github.com/mvkvc/rager_rb/actions/workflows/publish.yml)
|
5
5
|
[](https://github.com/mvkvc/rager_rb/actions/workflows/test.yml)
|
6
6
|
[](https://github.com/mvkvc/rager_rb/actions/workflows/lint.yml)
|
7
|
+
[](https://github.com/mvkvc/rager_rb/actions/workflows/docs.yml)
|
7
8
|
|
8
|
-
Build continuously improving
|
9
|
+
Build continuously improving generative workflows.
|
10
|
+
|
11
|
+
Examples are available in the [`examples/`](./examples/) folder.
|
9
12
|
|
10
13
|
## Installation
|
11
14
|
|
12
|
-
|
15
|
+
Add this line to your application's Gemfile:
|
13
16
|
|
14
|
-
```
|
15
|
-
|
17
|
+
```ruby
|
18
|
+
gem "rager", "~> 0.7.0"
|
16
19
|
```
|
17
20
|
|
18
|
-
|
21
|
+
Or use it in a standalone script (requires OPENAI_API_KEY set):
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require "bundler/inline"
|
25
|
+
|
26
|
+
gemfile do
|
27
|
+
source "https://rubygems.org"
|
28
|
+
gem "async-http", "~> 0.88.0"
|
29
|
+
gem "rager", "~> 0.7.0"
|
30
|
+
end
|
31
|
+
|
32
|
+
require "rager"
|
33
|
+
|
34
|
+
Rager.configure do |config|
|
35
|
+
config.http_adapter = Rager::Http::Adapters::AsyncHttp.new
|
36
|
+
end
|
37
|
+
|
38
|
+
PROMPT = ARGV[0] || "Ruby programming"
|
19
39
|
|
20
|
-
|
21
|
-
|
40
|
+
Async do
|
41
|
+
ctx = Rager::Context.new
|
42
|
+
prompt = ctx.template("Tell me about the history of <%= topic %>",{topic: PROMPT})
|
43
|
+
chat = ctx.chat(prompt, stream: true)
|
44
|
+
chat.stream.each { |d| print d.content }
|
45
|
+
end
|
22
46
|
```
|
23
47
|
|
48
|
+
## Providers
|
49
|
+
|
50
|
+
Modalities that take a URL parameter (chat, embedding, rerank) support compatible services, allowing you to use alternative providers that support the same interface.
|
51
|
+
|
52
|
+
| Feature | Providers |
|
53
|
+
| ---------------------- | ---------------- |
|
54
|
+
| **Chat** | `openai` |
|
55
|
+
| **Embedding** | `openai` |
|
56
|
+
| **Image generation** | `replicate` |
|
57
|
+
| **3D mesh generation** | `replicate` |
|
58
|
+
| **Reranking** | `cohere` |
|
59
|
+
| **Search** | `jina` |
|
60
|
+
| **Templating** | `erb`,`mustache` |
|
61
|
+
|
62
|
+
## Logging
|
63
|
+
|
64
|
+
The main reason for creating yet another library is to have out-of-the-box logging for workflows and outcomes. The logged data can then be used for few-shot prompting and fine-tuning. This logging server is being developed at [`rager.cloud`](https://rager.cloud) and is closed while I work on it. Contact me if you would like access.
|
65
|
+
|
24
66
|
## License
|
25
67
|
|
26
68
|
[MIT](./LICENSE.md)
|
data/lib/rager/chat/message.rb
CHANGED
@@ -6,8 +6,18 @@ require "sorbet-runtime"
|
|
6
6
|
module Rager
|
7
7
|
module Chat
|
8
8
|
class Message < T::Struct
|
9
|
+
extend T::Sig
|
10
|
+
|
9
11
|
const :role, MessageRole
|
10
12
|
const :content, T.any(String, T::Array[MessageContent])
|
13
|
+
|
14
|
+
sig { params(options: T.untyped).returns(String) }
|
15
|
+
def to_json(options = nil)
|
16
|
+
{
|
17
|
+
role: role,
|
18
|
+
content: content
|
19
|
+
}.to_json(options)
|
20
|
+
end
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
@@ -6,9 +6,16 @@ require "sorbet-runtime"
|
|
6
6
|
module Rager
|
7
7
|
module Chat
|
8
8
|
class MessageContent < T::Struct
|
9
|
+
extend T::Sig
|
10
|
+
|
9
11
|
const :type, MessageContentType, default: MessageContentType::Text
|
10
12
|
const :image_type, T.nilable(MessageContentImageType)
|
11
13
|
const :content, String
|
14
|
+
|
15
|
+
sig { params(options: T.untyped).returns(String) }
|
16
|
+
def to_json(options = nil)
|
17
|
+
serialize.to_json(options)
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
@@ -6,8 +6,15 @@ require "sorbet-runtime"
|
|
6
6
|
module Rager
|
7
7
|
module Chat
|
8
8
|
class MessageDelta < T::Struct
|
9
|
+
extend T::Sig
|
10
|
+
|
9
11
|
const :index, Integer, default: 0
|
10
12
|
const :content, String
|
13
|
+
|
14
|
+
sig { params(options: T.untyped).returns(String) }
|
15
|
+
def to_json(options = nil)
|
16
|
+
serialize.to_json(options)
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
13
20
|
end
|
data/lib/rager/chat/options.rb
CHANGED
@@ -10,20 +10,21 @@ module Rager
|
|
10
10
|
extend T::Sig
|
11
11
|
include Rager::Options
|
12
12
|
|
13
|
-
const :provider,
|
14
|
-
const :history, T::Array[Message], default: []
|
15
|
-
const :url, T.nilable(String)
|
16
|
-
const :api_key, T.nilable(String)
|
13
|
+
const :provider, Symbol, default: :openai
|
17
14
|
const :model, T.nilable(String)
|
18
15
|
const :stream, T.nilable(T::Boolean)
|
19
16
|
const :n, T.nilable(Integer)
|
20
17
|
const :temperature, T.nilable(Float)
|
18
|
+
const :max_tokens, T.nilable(Integer)
|
21
19
|
const :system_prompt, T.nilable(String)
|
22
20
|
const :schema, T.nilable(Dry::Schema::JSON)
|
23
21
|
const :schema_name, T.nilable(String)
|
24
22
|
const :seed, T.nilable(Integer)
|
23
|
+
const :url, T.nilable(String)
|
24
|
+
const :api_key, T.nilable(String)
|
25
|
+
const :timeout, T.nilable(Numeric)
|
25
26
|
|
26
|
-
sig { override.returns(T::Hash[
|
27
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
27
28
|
def serialize_safe
|
28
29
|
result = serialize
|
29
30
|
result["api_key"] = "[REDACTED]" if result.key?("api_key")
|
@@ -35,15 +36,17 @@ module Rager
|
|
35
36
|
def validate
|
36
37
|
if stream && schema
|
37
38
|
raise Rager::Errors::OptionsError.new(
|
38
|
-
|
39
|
-
|
39
|
+
self,
|
40
|
+
["stream", "schema"],
|
41
|
+
details: "You cannot use streaming with structured outputs"
|
40
42
|
)
|
41
43
|
end
|
42
44
|
|
43
45
|
if schema && schema_name.nil?
|
44
46
|
raise Rager::Errors::OptionsError.new(
|
45
|
-
|
46
|
-
|
47
|
+
self,
|
48
|
+
["schema", "schema_name"],
|
49
|
+
details: "You must provide a schema name when using structured outputs"
|
47
50
|
)
|
48
51
|
end
|
49
52
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "json"
|
5
|
+
|
5
6
|
require "sorbet-runtime"
|
6
7
|
|
7
8
|
module Rager
|
@@ -10,7 +11,8 @@ module Rager
|
|
10
11
|
class Openai < Rager::Chat::Providers::Abstract
|
11
12
|
extend T::Sig
|
12
13
|
|
13
|
-
|
14
|
+
OpenaiContentItem = T.type_alias { T::Hash[String, T.any(String, T::Hash[String, String])] }
|
15
|
+
OpenaiMessages = T.type_alias { T::Array[T::Hash[String, T.any(String, T::Array[OpenaiContentItem])]] }
|
14
16
|
|
15
17
|
sig do
|
16
18
|
override.params(
|
@@ -20,14 +22,24 @@ module Rager
|
|
20
22
|
end
|
21
23
|
def chat(messages, options)
|
22
24
|
api_key = options.api_key || ENV["OPENAI_API_KEY"]
|
23
|
-
raise Rager::Errors::
|
25
|
+
raise Rager::Errors::CredentialsError.new("OpenAI", env_var: ["OPENAI_API_KEY"]) if api_key.nil?
|
26
|
+
|
27
|
+
base_url = options.url || ENV["OPENAI_URL"] || "https://api.openai.com/v1"
|
28
|
+
url = "#{base_url}/chat/completions"
|
29
|
+
|
30
|
+
headers = {
|
31
|
+
"Content-Type" => "application/json"
|
32
|
+
}.tap do |h|
|
33
|
+
h["Authorization"] = "Bearer #{api_key}" if api_key
|
34
|
+
end
|
24
35
|
|
25
36
|
body = {
|
26
37
|
model: options.model || "gpt-4.1",
|
27
|
-
messages: build_openai_messages(messages, options.
|
38
|
+
messages: build_openai_messages(messages, options.system_prompt)
|
28
39
|
}.tap do |b|
|
29
|
-
b[:temperature] = options.temperature if options.temperature
|
30
40
|
b[:n] = options.n if options.n
|
41
|
+
b[:max_tokens] = options.max_tokens if options.max_tokens
|
42
|
+
b[:temperature] = options.temperature if options.temperature
|
31
43
|
b[:stream] = options.stream if options.stream
|
32
44
|
b[:seed] = options.seed if options.seed
|
33
45
|
|
@@ -43,20 +55,19 @@ module Rager
|
|
43
55
|
end
|
44
56
|
end
|
45
57
|
|
46
|
-
headers = {"Content-Type" => "application/json"}
|
47
|
-
headers["Authorization"] = "Bearer #{api_key}" if api_key
|
48
|
-
|
49
58
|
request = Rager::Http::Request.new(
|
50
59
|
verb: Rager::Http::Verb::Post,
|
51
|
-
url:
|
60
|
+
url: url,
|
52
61
|
headers: headers,
|
53
|
-
body: body.to_json
|
62
|
+
body: body.to_json,
|
63
|
+
streaming: options.stream || false,
|
64
|
+
timeout: options.timeout || Rager.config.timeout
|
54
65
|
)
|
55
66
|
|
56
67
|
response = Rager.config.http_adapter.make_request(request)
|
57
68
|
response_body = T.must(response.body)
|
58
69
|
|
59
|
-
raise Rager::Errors::HttpError.new(Rager.config.http_adapter, response.status, T.cast(response_body, String)) if response.status != 200
|
70
|
+
raise Rager::Errors::HttpError.new(Rager.config.http_adapter, request.url, response.status, body: T.cast(response_body, String)) if response.status != 200
|
60
71
|
|
61
72
|
case response_body
|
62
73
|
when String then handle_non_stream_body(response_body)
|
@@ -64,39 +75,36 @@ module Rager
|
|
64
75
|
end
|
65
76
|
end
|
66
77
|
|
67
|
-
private
|
68
|
-
|
69
78
|
sig do
|
70
79
|
params(
|
71
80
|
messages: T::Array[Rager::Chat::Message],
|
72
|
-
history: T::Array[Rager::Chat::Message],
|
73
81
|
system_prompt: T.nilable(String)
|
74
82
|
).returns(OpenaiMessages)
|
75
83
|
end
|
76
|
-
def build_openai_messages(messages,
|
77
|
-
|
84
|
+
def build_openai_messages(messages, system_prompt)
|
85
|
+
output = T.let([], OpenaiMessages)
|
78
86
|
|
79
|
-
if
|
80
|
-
|
87
|
+
if system_prompt
|
88
|
+
output << {"role" => "system", "content" => system_prompt}
|
81
89
|
end
|
82
90
|
|
83
|
-
|
91
|
+
messages.each do |message|
|
84
92
|
role = message.role.is_a?(String) ? message.role : message.role.serialize
|
85
93
|
content = message.content
|
86
94
|
|
87
95
|
case content
|
88
96
|
when String
|
89
|
-
|
97
|
+
output << {"role" => role, "content" => content}
|
90
98
|
when Array
|
91
99
|
formatted_content = content.map { |item| format_content_item(item) }
|
92
|
-
|
100
|
+
output << {"role" => role, "content" => formatted_content}
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
96
|
-
|
104
|
+
output
|
97
105
|
end
|
98
106
|
|
99
|
-
sig { params(item: Rager::Chat::MessageContent).returns(
|
107
|
+
sig { params(item: Rager::Chat::MessageContent).returns(OpenaiContentItem) }
|
100
108
|
def format_content_item(item)
|
101
109
|
case item.type
|
102
110
|
when Rager::Chat::MessageContentType::Text
|
@@ -113,48 +121,56 @@ module Rager
|
|
113
121
|
end
|
114
122
|
end
|
115
123
|
|
116
|
-
sig { params(body: String).returns(
|
124
|
+
sig { params(body: String).returns(Rager::Types::ChatNonStreamOutput) }
|
117
125
|
def handle_non_stream_body(body)
|
118
126
|
response_data = JSON.parse(body)
|
119
127
|
return [] unless response_data.key?("choices") && response_data["choices"].is_a?(Array)
|
120
128
|
|
121
|
-
response_data["choices"].filter_map do |choice|
|
129
|
+
result = response_data["choices"].filter_map do |choice|
|
122
130
|
text = choice.dig("message", "content").to_s
|
123
131
|
text unless text.empty?
|
124
132
|
end
|
133
|
+
|
134
|
+
result.one? ? result.first : result
|
125
135
|
rescue JSON::ParserError
|
126
|
-
raise Rager::Errors::ParseError.new("OpenAI response body is not valid JSON"
|
136
|
+
raise Rager::Errors::ParseError.new(body, details: "OpenAI response body is not valid JSON")
|
127
137
|
end
|
128
138
|
|
129
139
|
sig { params(body: T::Enumerator[String]).returns(T::Enumerator[Rager::Chat::MessageDelta]) }
|
130
140
|
def handle_stream_body(body)
|
131
141
|
Enumerator.new do |yielder|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
buffer
|
136
|
-
while (
|
137
|
-
|
138
|
-
data_line = match[1] || match[2]
|
139
|
-
|
140
|
-
next if data_line.nil? || data_line.strip.empty? || data_line.strip == "[DONE]"
|
141
|
-
|
142
|
-
begin
|
143
|
-
data = JSON.parse(data_line)
|
144
|
-
next unless data.key?("choices") && data["choices"].is_a?(Array)
|
145
|
-
|
146
|
-
data["choices"].each do |choice|
|
147
|
-
delta = choice.dig("delta", "content")
|
148
|
-
yielder << Rager::Chat::MessageDelta.new(index: choice.dig("index") || 0, content: delta) if delta
|
149
|
-
end
|
150
|
-
rescue JSON::ParserError
|
151
|
-
next
|
152
|
-
end
|
142
|
+
buffer_parts = []
|
143
|
+
body.each do |chunk|
|
144
|
+
buffer_parts << chunk.force_encoding(Encoding::UTF_8)
|
145
|
+
buffer = buffer_parts.join
|
146
|
+
while (line = buffer.slice!(/.*\n/))
|
147
|
+
process_stream_line(line, yielder)
|
153
148
|
end
|
149
|
+
buffer_parts = buffer.empty? ? [] : [buffer]
|
154
150
|
end
|
155
151
|
|
156
|
-
|
157
|
-
|
152
|
+
unless buffer_parts.empty?
|
153
|
+
process_stream_line(buffer_parts.join, yielder)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
sig { params(line: String, yielder: Enumerator::Yielder).void.checked(:never) }
|
161
|
+
def process_stream_line(line, yielder)
|
162
|
+
line.delete_prefix!("data: ") or return
|
163
|
+
line.strip!
|
164
|
+
return if line.empty? || line == "[DONE]"
|
165
|
+
|
166
|
+
begin
|
167
|
+
JSON.parse(line).dig("choices")&.each do |choice|
|
168
|
+
if (content = choice.dig("delta", "content"))
|
169
|
+
yielder << Rager::Chat::MessageDelta.new(index: choice["index"] || 0, content: content)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
rescue JSON::ParserError
|
173
|
+
nil
|
158
174
|
end
|
159
175
|
end
|
160
176
|
end
|
data/lib/rager/chat/schema.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "dry-schema"
|
5
4
|
require "json"
|
5
|
+
|
6
|
+
require "dry-schema"
|
6
7
|
require "sorbet-runtime"
|
7
8
|
|
8
9
|
Dry::Schema.load_extensions(:json_schema)
|
@@ -15,7 +16,7 @@ module Rager
|
|
15
16
|
sig { params(schema: Dry::Schema::JSON).returns(T::Hash[Symbol, T.untyped]) }
|
16
17
|
def self.dry_schema_to_json_schema(schema)
|
17
18
|
json_schema_original = schema.json_schema
|
18
|
-
json_schema = JSON.parse(JSON.generate(json_schema_original)
|
19
|
+
json_schema = JSON.parse(JSON.generate(json_schema_original))
|
19
20
|
|
20
21
|
make_strict_recursive!(json_schema)
|
21
22
|
|
@@ -41,8 +42,6 @@ module Rager
|
|
41
42
|
node.each { |item| make_strict_recursive!(item) }
|
42
43
|
end
|
43
44
|
end
|
44
|
-
|
45
|
-
private_class_method :make_strict_recursive!
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
data/lib/rager/config.rb
CHANGED
@@ -7,40 +7,36 @@ module Rager
|
|
7
7
|
class Config
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
sig { returns(T.nilable(Rager::Logger)) }
|
11
|
-
attr_accessor :logger_type
|
12
|
-
|
13
10
|
sig { returns(::Logger) }
|
14
11
|
attr_accessor :logger
|
15
12
|
|
13
|
+
sig { returns(T::Boolean) }
|
14
|
+
attr_accessor :log_raise
|
15
|
+
|
16
|
+
sig { returns(Rager::LogStrategy) }
|
17
|
+
attr_accessor :log_strategy
|
18
|
+
|
19
|
+
sig { returns(Rager::Http::Adapters::Abstract) }
|
20
|
+
attr_accessor :http_adapter
|
21
|
+
|
16
22
|
sig { returns(T.nilable(String)) }
|
17
23
|
attr_accessor :url
|
18
24
|
|
19
25
|
sig { returns(T.nilable(String)) }
|
20
26
|
attr_accessor :api_key
|
21
27
|
|
28
|
+
sig { returns(T.nilable(Numeric)) }
|
29
|
+
attr_accessor :timeout
|
30
|
+
|
22
31
|
sig { void }
|
23
32
|
def initialize
|
24
|
-
@http_adapter = T.let(nil, T.nilable(Rager::Http::Adapters::Abstract))
|
25
|
-
@logger_type = T.let(nil, T.nilable(Rager::Logger))
|
26
33
|
@logger = T.let(::Logger.new($stdout), ::Logger)
|
34
|
+
@log_raise = T.let(false, T::Boolean)
|
35
|
+
@log_strategy = T.let(Rager::LogStrategy::None, Rager::LogStrategy)
|
36
|
+
@http_adapter = T.let(Rager::Http::Adapters::NetHttp.new, Rager::Http::Adapters::Abstract)
|
27
37
|
@url = T.let(nil, T.nilable(String))
|
28
38
|
@api_key = T.let(nil, T.nilable(String))
|
29
|
-
|
30
|
-
|
31
|
-
sig { returns(Rager::Http::Adapters::Abstract) }
|
32
|
-
def http_adapter
|
33
|
-
@http_adapter ||= default_http_adapter
|
34
|
-
end
|
35
|
-
|
36
|
-
sig { params(http_adapter: Rager::Http::Adapters::Abstract).void }
|
37
|
-
attr_writer :http_adapter
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
sig { returns(Rager::Http::Adapters::Abstract) }
|
42
|
-
def default_http_adapter
|
43
|
-
Rager::Http::Adapters::AsyncHttp.new
|
39
|
+
@timeout = T.let(nil, T.nilable(Numeric))
|
44
40
|
end
|
45
41
|
end
|
46
42
|
end
|