llm.rb 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +165 -2
  3. data/README.md +161 -509
  4. data/data/bedrock.json +2948 -0
  5. data/data/deepseek.json +8 -8
  6. data/data/openai.json +39 -2
  7. data/data/xai.json +35 -0
  8. data/data/zai.json +1 -1
  9. data/lib/llm/active_record/acts_as_llm.rb +7 -8
  10. data/lib/llm/agent.rb +36 -16
  11. data/lib/llm/context.rb +30 -26
  12. data/lib/llm/contract/completion.rb +45 -0
  13. data/lib/llm/cost.rb +81 -4
  14. data/lib/llm/error.rb +1 -1
  15. data/lib/llm/function/array.rb +8 -5
  16. data/lib/llm/function/call_group.rb +39 -0
  17. data/lib/llm/function/fork/task.rb +6 -0
  18. data/lib/llm/function/ractor/task.rb +6 -0
  19. data/lib/llm/function/task.rb +10 -0
  20. data/lib/llm/function.rb +1 -0
  21. data/lib/llm/mcp/transport/http.rb +26 -46
  22. data/lib/llm/mcp/transport/stdio.rb +0 -8
  23. data/lib/llm/mcp.rb +6 -23
  24. data/lib/llm/object.rb +8 -0
  25. data/lib/llm/provider.rb +29 -19
  26. data/lib/llm/providers/anthropic/error_handler.rb +6 -7
  27. data/lib/llm/providers/anthropic/files.rb +2 -2
  28. data/lib/llm/providers/anthropic/response_adapter/completion.rb +30 -0
  29. data/lib/llm/providers/anthropic.rb +1 -1
  30. data/lib/llm/providers/bedrock/error_handler.rb +79 -0
  31. data/lib/llm/providers/bedrock/models.rb +109 -0
  32. data/lib/llm/providers/bedrock/request_adapter/completion.rb +153 -0
  33. data/lib/llm/providers/bedrock/request_adapter.rb +95 -0
  34. data/lib/llm/providers/bedrock/response_adapter/completion.rb +173 -0
  35. data/lib/llm/providers/bedrock/response_adapter/models.rb +34 -0
  36. data/lib/llm/providers/bedrock/response_adapter.rb +40 -0
  37. data/lib/llm/providers/bedrock/signature.rb +166 -0
  38. data/lib/llm/providers/bedrock/stream_decoder.rb +140 -0
  39. data/lib/llm/providers/bedrock/stream_parser.rb +201 -0
  40. data/lib/llm/providers/bedrock.rb +272 -0
  41. data/lib/llm/providers/google/error_handler.rb +6 -7
  42. data/lib/llm/providers/google/files.rb +2 -4
  43. data/lib/llm/providers/google/images.rb +1 -1
  44. data/lib/llm/providers/google/models.rb +0 -2
  45. data/lib/llm/providers/google/response_adapter/completion.rb +30 -0
  46. data/lib/llm/providers/google.rb +1 -1
  47. data/lib/llm/providers/ollama/error_handler.rb +6 -7
  48. data/lib/llm/providers/ollama/models.rb +0 -2
  49. data/lib/llm/providers/ollama/response_adapter/completion.rb +30 -0
  50. data/lib/llm/providers/ollama.rb +1 -1
  51. data/lib/llm/providers/openai/audio.rb +3 -3
  52. data/lib/llm/providers/openai/error_handler.rb +6 -7
  53. data/lib/llm/providers/openai/files.rb +2 -2
  54. data/lib/llm/providers/openai/images.rb +3 -3
  55. data/lib/llm/providers/openai/models.rb +1 -1
  56. data/lib/llm/providers/openai/response_adapter/completion.rb +42 -0
  57. data/lib/llm/providers/openai/response_adapter/responds.rb +39 -0
  58. data/lib/llm/providers/openai/responses.rb +2 -2
  59. data/lib/llm/providers/openai/vector_stores.rb +1 -1
  60. data/lib/llm/providers/openai.rb +1 -1
  61. data/lib/llm/response.rb +10 -8
  62. data/lib/llm/sequel/plugin.rb +7 -8
  63. data/lib/llm/stream/queue.rb +15 -42
  64. data/lib/llm/stream.rb +4 -4
  65. data/lib/llm/transport/execution.rb +67 -0
  66. data/lib/llm/transport/http.rb +134 -0
  67. data/lib/llm/transport/persistent_http.rb +152 -0
  68. data/lib/llm/transport/response/http.rb +113 -0
  69. data/lib/llm/transport/response.rb +112 -0
  70. data/lib/llm/{provider/transport/http → transport}/stream_decoder.rb +8 -4
  71. data/lib/llm/transport.rb +139 -0
  72. data/lib/llm/usage.rb +14 -5
  73. data/lib/llm/version.rb +1 -1
  74. data/lib/llm.rb +10 -12
  75. data/llm.gemspec +2 -16
  76. metadata +23 -19
  77. data/lib/llm/provider/transport/http/execution.rb +0 -115
  78. data/lib/llm/provider/transport/http/interruptible.rb +0 -114
  79. data/lib/llm/provider/transport/http.rb +0 -145
  80. data/lib/llm/utils.rb +0 -19
data/lib/llm.rb CHANGED
@@ -14,8 +14,8 @@ module LLM
14
14
  require_relative "llm/object"
15
15
  require_relative "llm/model"
16
16
  require_relative "llm/version"
17
- require_relative "llm/utils"
18
17
  require_relative "llm/message"
18
+ require_relative "llm/transport"
19
19
  require_relative "llm/response"
20
20
  require_relative "llm/mime"
21
21
  require_relative "llm/multipart"
@@ -37,22 +37,12 @@ module LLM
37
37
 
38
38
  ##
39
39
  # Thread-safe monitors for different contexts
40
- @monitors = {require: Monitor.new, clients: Monitor.new, inherited: Monitor.new, registry: Monitor.new, mcp: Monitor.new}
40
+ @monitors = {require: Monitor.new, inherited: Monitor.new, registry: Monitor.new, mcp: Monitor.new}
41
41
 
42
42
  ##
43
43
  # Model registry
44
44
  @registry = {}
45
45
 
46
- ##
47
- # Shared HTTP clients used by providers.
48
- @clients = {}
49
-
50
- ##
51
- # @api private
52
- def self.clients
53
- @clients
54
- end
55
-
56
46
  ##
57
47
  # Requires an optional runtime dependency
58
48
  # @raise [LLM::DependencyError]
@@ -161,6 +151,14 @@ module LLM
161
151
  LLM::OpenAI.new(**)
162
152
  end
163
153
 
154
+ ##
155
+ # @param (see LLM::Bedrock#initialize)
156
+ # @return (see LLM::Bedrock#initialize)
157
+ def bedrock(**)
158
+ lock(:require) { require_relative "llm/providers/bedrock" unless defined?(LLM::Bedrock) }
159
+ LLM::Bedrock.new(**)
160
+ end
161
+
164
162
  ##
165
163
  # @param key (see LLM::XAI#initialize)
166
164
  # @param host (see LLM::XAI#initialize)
data/llm.gemspec CHANGED
@@ -8,22 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Antar Azri", "0x1eef", "Christos Maris", "Rodrigo Serrano"]
9
9
  spec.email = ["azantar@proton.me", "0x1eef@hardenedbsd.org"]
10
10
 
11
- spec.summary = "Lightweight runtime for building capable AI systems in Ruby."
12
-
13
- spec.description = <<~DESCRIPTION
14
- llm.rb is a lightweight runtime for building capable AI systems in Ruby.
15
- It is not just an API wrapper. llm.rb gives you one runtime for providers,
16
- contexts, agents, tools, MCP servers, streaming, schemas, files, and
17
- persisted state, so real systems can be built out of one coherent
18
- execution model instead of a pile of adapters. It stays close to Ruby, runs
19
- on the standard library by default, loads optional pieces only when needed,
20
- includes built-in ActiveRecord support through acts_as_llm and
21
- acts_as_agent, includes built-in Sequel support through plugin :llm,
22
- and is designed for engineers who want control over long-lived,
23
- tool-capable, stateful AI workflows instead of just request/response
24
- helpers.
25
- DESCRIPTION
26
-
11
+ spec.summary = "Ruby's most capable AI runtime"
12
+ spec.description = spec.summary
27
13
  spec.license = "0BSD"
28
14
  spec.required_ruby_version = ">= 3.3.0"
29
15
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antar Azri
@@ -264,18 +264,7 @@ dependencies:
264
264
  - - "~>"
265
265
  - !ruby/object:Gem::Version
266
266
  version: '1.5'
267
- description: |
268
- llm.rb is a lightweight runtime for building capable AI systems in Ruby.
269
- It is not just an API wrapper. llm.rb gives you one runtime for providers,
270
- contexts, agents, tools, MCP servers, streaming, schemas, files, and
271
- persisted state, so real systems can be built out of one coherent
272
- execution model instead of a pile of adapters. It stays close to Ruby, runs
273
- on the standard library by default, loads optional pieces only when needed,
274
- includes built-in ActiveRecord support through acts_as_llm and
275
- acts_as_agent, includes built-in Sequel support through plugin :llm,
276
- and is designed for engineers who want control over long-lived,
277
- tool-capable, stateful AI workflows instead of just request/response
278
- helpers.
267
+ description: Ruby's most capable AI runtime
279
268
  email:
280
269
  - azantar@proton.me
281
270
  - 0x1eef@hardenedbsd.org
@@ -287,6 +276,7 @@ files:
287
276
  - LICENSE
288
277
  - README.md
289
278
  - data/anthropic.json
279
+ - data/bedrock.json
290
280
  - data/deepseek.json
291
281
  - data/google.json
292
282
  - data/openai.json
@@ -314,6 +304,7 @@ files:
314
304
  - lib/llm/file.rb
315
305
  - lib/llm/function.rb
316
306
  - lib/llm/function/array.rb
307
+ - lib/llm/function/call_group.rb
317
308
  - lib/llm/function/fiber_group.rb
318
309
  - lib/llm/function/fork.rb
319
310
  - lib/llm/function/fork/job.rb
@@ -351,10 +342,6 @@ files:
351
342
  - lib/llm/pipe.rb
352
343
  - lib/llm/prompt.rb
353
344
  - lib/llm/provider.rb
354
- - lib/llm/provider/transport/http.rb
355
- - lib/llm/provider/transport/http/execution.rb
356
- - lib/llm/provider/transport/http/interruptible.rb
357
- - lib/llm/provider/transport/http/stream_decoder.rb
358
345
  - lib/llm/providers/anthropic.rb
359
346
  - lib/llm/providers/anthropic/error_handler.rb
360
347
  - lib/llm/providers/anthropic/files.rb
@@ -369,6 +356,17 @@ files:
369
356
  - lib/llm/providers/anthropic/response_adapter/web_search.rb
370
357
  - lib/llm/providers/anthropic/stream_parser.rb
371
358
  - lib/llm/providers/anthropic/utils.rb
359
+ - lib/llm/providers/bedrock.rb
360
+ - lib/llm/providers/bedrock/error_handler.rb
361
+ - lib/llm/providers/bedrock/models.rb
362
+ - lib/llm/providers/bedrock/request_adapter.rb
363
+ - lib/llm/providers/bedrock/request_adapter/completion.rb
364
+ - lib/llm/providers/bedrock/response_adapter.rb
365
+ - lib/llm/providers/bedrock/response_adapter/completion.rb
366
+ - lib/llm/providers/bedrock/response_adapter/models.rb
367
+ - lib/llm/providers/bedrock/signature.rb
368
+ - lib/llm/providers/bedrock/stream_decoder.rb
369
+ - lib/llm/providers/bedrock/stream_parser.rb
372
370
  - lib/llm/providers/deepseek.rb
373
371
  - lib/llm/providers/deepseek/request_adapter.rb
374
372
  - lib/llm/providers/deepseek/request_adapter/completion.rb
@@ -461,8 +459,14 @@ files:
461
459
  - lib/llm/tracer/logger.rb
462
460
  - lib/llm/tracer/null.rb
463
461
  - lib/llm/tracer/telemetry.rb
462
+ - lib/llm/transport.rb
463
+ - lib/llm/transport/execution.rb
464
+ - lib/llm/transport/http.rb
465
+ - lib/llm/transport/persistent_http.rb
466
+ - lib/llm/transport/response.rb
467
+ - lib/llm/transport/response/http.rb
468
+ - lib/llm/transport/stream_decoder.rb
464
469
  - lib/llm/usage.rb
465
- - lib/llm/utils.rb
466
470
  - lib/llm/version.rb
467
471
  - lib/sequel/plugins/agent.rb
468
472
  - lib/sequel/plugins/llm.rb
@@ -491,5 +495,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
491
495
  requirements: []
492
496
  rubygems_version: 4.0.3
493
497
  specification_version: 4
494
- summary: Lightweight runtime for building capable AI systems in Ruby.
498
+ summary: Ruby's most capable AI runtime
495
499
  test_files: []
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LLM::Provider::Transport
4
- class HTTP
5
- ##
6
- # Internal HTTP request execution methods for {LLM::Provider}.
7
- #
8
- # This module handles provider-side HTTP execution, response parsing,
9
- # streaming, and request body setup through
10
- # {LLM::Provider::Transport::HTTP}.
11
- #
12
- # @api private
13
- module HTTP::Execution
14
- private
15
-
16
- ##
17
- # Executes a HTTP request
18
- # @param [Net::HTTPRequest] request
19
- # The request to send
20
- # @param [Proc] b
21
- # A block to yield the response to (optional)
22
- # @return [Net::HTTPResponse]
23
- # The response from the server
24
- # @raise [LLM::Error::Unauthorized]
25
- # When authentication fails
26
- # @raise [LLM::Error::RateLimit]
27
- # When the rate limit is exceeded
28
- # @raise [LLM::Error]
29
- # When any other unsuccessful status code is returned
30
- # @raise [SystemCallError]
31
- # When there is a network error at the operating system level
32
- # @return [Net::HTTPResponse]
33
- def execute(request:, operation:, stream: nil, stream_parser: self.stream_parser, model: nil, inputs: nil, &b)
34
- owner = transport.request_owner
35
- tracer = self.tracer
36
- span = tracer.on_request_start(operation:, model:, inputs:)
37
- res = transport.request(request, owner:) do |http|
38
- perform_request(http, request, stream, stream_parser, &b)
39
- end
40
- [handle_response(res, tracer, span), span, tracer]
41
- rescue *transport.interrupt_errors
42
- raise LLM::Interrupt, "request interrupted" if transport.interrupted?(owner)
43
- raise
44
- end
45
-
46
- ##
47
- # Handles the response from a request
48
- # @param [Net::HTTPResponse] res
49
- # The response to handle
50
- # @param [Object, nil] span
51
- # The span
52
- # @return [Net::HTTPResponse]
53
- def handle_response(res, tracer, span)
54
- case res
55
- when Net::HTTPOK then res.body = parse_response(res)
56
- else error_handler.new(tracer, span, res).raise_error!
57
- end
58
- res
59
- end
60
-
61
- ##
62
- # Parse a HTTP response
63
- # @param [Net::HTTPResponse] res
64
- # @return [LLM::Object, String]
65
- def parse_response(res)
66
- case res["content-type"]
67
- when %r{\Aapplication/json\s*} then LLM::Object.from(LLM.json.load(res.body))
68
- else res.body
69
- end
70
- end
71
-
72
- ##
73
- # @param [Net::HTTPRequest] req
74
- # The request to set the body stream for
75
- # @param [IO] io
76
- # The IO object to set as the body stream
77
- # @return [void]
78
- def set_body_stream(req, io)
79
- req.body_stream = io
80
- req["transfer-encoding"] = "chunked" unless req["content-length"]
81
- end
82
-
83
- ##
84
- # Performs the request on the given HTTP connection.
85
- # @param [Net::HTTP] http
86
- # @param [Net::HTTPRequest] request
87
- # @param [Object, nil] stream
88
- # @param [Class] stream_parser
89
- # @param [Proc, nil] b
90
- # @return [Net::HTTPResponse]
91
- def perform_request(http, request, stream, stream_parser, &b)
92
- if stream
93
- http.request(request) do |res|
94
- if Net::HTTPSuccess === res
95
- parser = StreamDecoder.new(stream_parser.new(stream))
96
- res.read_body(parser)
97
- body = parser.body
98
- res.body = (Hash === body || Array === body) ? LLM::Object.from(body) : body
99
- else
100
- body = +""
101
- res.read_body { body << _1 }
102
- res.body = body
103
- end
104
- ensure
105
- parser&.free
106
- end
107
- elsif b
108
- http.request(request) { (Net::HTTPSuccess === _1) ? b.call(_1) : _1 }
109
- else
110
- http.request(request)
111
- end
112
- end
113
- end
114
- end
115
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class LLM::Provider
4
- ##
5
- # Internal request interruption methods for
6
- # {LLM::Provider::Transport::HTTP}.
7
- #
8
- # This module tracks active requests by execution owner and provides
9
- # the logic used to interrupt an in-flight request by closing the
10
- # active HTTP connection.
11
- #
12
- # @api private
13
- module Transport::HTTP::Interruptible
14
- INTERRUPT_ERRORS = [::IOError, ::EOFError, Errno::EBADF].freeze
15
- Request = Struct.new(:http, :connection, keyword_init: true)
16
-
17
- def interrupt_errors
18
- [*INTERRUPT_ERRORS, *optional_interrupt_errors]
19
- end
20
-
21
- ##
22
- # Interrupt an active request, if any.
23
- # @param [Fiber] owner
24
- # The execution owner whose request should be interrupted
25
- # @return [nil]
26
- def interrupt!(owner)
27
- req = request_for(owner) or return
28
- lock { (@interrupts ||= {})[owner] = true }
29
- if persistent_http?(req.http)
30
- close_socket(req.connection&.http)
31
- req.http.finish(req.connection)
32
- elsif transient_http?(req.http)
33
- close_socket(req.http)
34
- req.http.finish if req.http.active?
35
- end
36
- owner.stop if owner.respond_to?(:stop)
37
- rescue *interrupt_errors
38
- nil
39
- end
40
-
41
- private
42
-
43
- ##
44
- # Closes the active socket for a request, if present.
45
- # @param [Net::HTTP, nil] http
46
- # @return [nil]
47
- def close_socket(http)
48
- socket = http&.instance_variable_get(:@socket) or return
49
- socket = socket.io if socket.respond_to?(:io)
50
- socket.close
51
- rescue *interrupt_errors
52
- nil
53
- end
54
-
55
- ##
56
- # Returns whether the active request is using a transient HTTP client.
57
- # @param [Object, nil] http
58
- # @return [Boolean]
59
- def transient_http?(http)
60
- Net::HTTP === http
61
- end
62
-
63
- ##
64
- # Returns whether the active request is using a persistent HTTP client.
65
- # @param [Object, nil] http
66
- # @return [Boolean]
67
- def persistent_http?(http)
68
- defined?(Net::HTTP::Persistent) && Net::HTTP::Persistent === http
69
- end
70
-
71
- ##
72
- # Returns the active request for an execution owner.
73
- # @param [Fiber] owner
74
- # @return [Request, nil]
75
- def request_for(owner)
76
- lock do
77
- @requests ||= {}
78
- @requests[owner]
79
- end
80
- end
81
-
82
- ##
83
- # Records an active request for an execution owner.
84
- # @param [Request] req
85
- # @param [Fiber] owner
86
- # @return [Request]
87
- def set_request(req, owner)
88
- lock do
89
- @requests ||= {}
90
- @requests[owner] = req
91
- end
92
- end
93
-
94
- ##
95
- # Clears the active request for an execution owner.
96
- # @param [Fiber] owner
97
- # @return [Request, nil]
98
- def clear_request(owner)
99
- lock { @requests&.delete(owner) }
100
- end
101
-
102
- ##
103
- # Returns whether an execution owner was interrupted.
104
- # @param [Fiber] owner
105
- # @return [Boolean, nil]
106
- def interrupted?(owner)
107
- lock { @interrupts&.delete(owner) }
108
- end
109
-
110
- def optional_interrupt_errors
111
- defined?(::Async::Stop) ? [Async::Stop] : []
112
- end
113
- end
114
- end
@@ -1,145 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class LLM::Provider
4
- module Transport
5
- ##
6
- # The {LLM::Provider::Transport::HTTP LLM::Provider::Transport::HTTP}
7
- # class manages HTTP connections for {LLM::Provider}. It handles
8
- # transient and persistent clients, tracks active requests by owner,
9
- # and interrupts in-flight requests when needed.
10
- #
11
- # @api private
12
- class HTTP
13
- require_relative "http/stream_decoder"
14
- require_relative "http/interruptible"
15
-
16
- include Interruptible
17
-
18
- ##
19
- # @param [String] host
20
- # @param [Integer] port
21
- # @param [Integer] timeout
22
- # @param [Boolean] ssl
23
- # @param [Boolean] persistent
24
- # @return [LLM::Provider::Transport::HTTP]
25
- def initialize(host:, port:, timeout:, ssl:, persistent: false)
26
- @host = host
27
- @port = port
28
- @timeout = timeout
29
- @ssl = ssl
30
- @base_uri = URI("#{ssl ? "https" : "http"}://#{host}:#{port}/")
31
- @persistent_client = persistent ? persistent_client : nil
32
- @monitor = Monitor.new
33
- end
34
-
35
- ##
36
- # Interrupt an active request, if any.
37
- # @param [Fiber] owner
38
- # @return [nil]
39
- def interrupt!(owner)
40
- super
41
- end
42
-
43
- ##
44
- # Returns whether an execution owner was interrupted.
45
- # @param [Fiber] owner
46
- # @return [Boolean, nil]
47
- def interrupted?(owner)
48
- super
49
- end
50
-
51
- ##
52
- # Returns the current request owner.
53
- # @return [Object]
54
- def request_owner
55
- return Fiber.current unless defined?(::Async)
56
- Async::Task.current? ? Async::Task.current : Fiber.current
57
- end
58
-
59
- ##
60
- # Configures the transport to use a persistent HTTP connection pool.
61
- # @return [LLM::Provider::Transport::HTTP]
62
- def persist!
63
- client = persistent_client
64
- lock do
65
- @persistent_client = client
66
- self
67
- end
68
- end
69
- alias_method :persistent, :persist!
70
-
71
- ##
72
- # @return [Boolean]
73
- def persistent?
74
- !@persistent_client.nil?
75
- end
76
-
77
- ##
78
- # Performs a request on the current HTTP transport.
79
- # @param [Net::HTTPRequest] request
80
- # @param [Fiber] owner
81
- # @yieldparam [Net::HTTP] http
82
- # @return [Object]
83
- def request(request, owner:, &)
84
- if persistent?
85
- request_persistent(request, owner, &)
86
- else
87
- request_transient(request, owner, &)
88
- end
89
- ensure
90
- clear_request(owner)
91
- end
92
-
93
- ##
94
- # @return [String]
95
- def inspect
96
- "#<#{self.class.name}:0x#{object_id.to_s(16)} @persistent=#{persistent?}>"
97
- end
98
-
99
- private
100
-
101
- attr_reader :host, :port, :timeout, :ssl, :base_uri
102
-
103
- def request_transient(request, owner, &)
104
- http = transient_client
105
- set_request(Request.new(http:), owner)
106
- yield http
107
- end
108
-
109
- def request_persistent(request, owner, &)
110
- persistent_client.connection_for(URI.join(base_uri, request.path)) do |connection|
111
- set_request(Request.new(http: persistent_client, connection:), owner)
112
- yield connection.http
113
- end
114
- end
115
-
116
- def persistent_client
117
- LLM.lock(:clients) do
118
- if LLM.clients[client_id]
119
- LLM.clients[client_id]
120
- else
121
- require "net/http/persistent" unless defined?(Net::HTTP::Persistent)
122
- client = Net::HTTP::Persistent.new(name: self.class.name)
123
- client.read_timeout = timeout
124
- LLM.clients[client_id] = client
125
- end
126
- end
127
- end
128
-
129
- def transient_client
130
- client = Net::HTTP.new(host, port)
131
- client.read_timeout = timeout
132
- client.use_ssl = ssl
133
- client
134
- end
135
-
136
- def client_id
137
- "#{host}:#{port}:#{timeout}:#{ssl}"
138
- end
139
-
140
- def lock(&)
141
- @monitor.synchronize(&)
142
- end
143
- end
144
- end
145
- end
data/lib/llm/utils.rb DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ##
4
- # @private
5
- module LLM::Utils
6
- def camelcase(key)
7
- key.to_s
8
- .split("_")
9
- .map.with_index { (_2 > 0) ? _1.capitalize : _1 }
10
- .join
11
- end
12
-
13
- def snakecase(key)
14
- key
15
- .split(/([A-Z])/)
16
- .map { (_1.size == 1) ? "_#{_1.downcase}" : _1 }
17
- .join
18
- end
19
- end