llm.rb 4.1.0 → 4.3.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/README.md +241 -166
  4. data/lib/llm/agent.rb +65 -37
  5. data/lib/llm/bot.rb +118 -30
  6. data/lib/llm/buffer.rb +6 -0
  7. data/lib/llm/function/tracing.rb +19 -0
  8. data/lib/llm/function.rb +28 -3
  9. data/lib/llm/json_adapter.rb +12 -12
  10. data/lib/llm/message.rb +19 -4
  11. data/lib/llm/prompt.rb +85 -0
  12. data/lib/llm/provider.rb +62 -10
  13. data/lib/llm/providers/anthropic/error_handler.rb +27 -5
  14. data/lib/llm/providers/anthropic/files.rb +22 -16
  15. data/lib/llm/providers/anthropic/models.rb +4 -3
  16. data/lib/llm/providers/anthropic.rb +6 -5
  17. data/lib/llm/providers/deepseek.rb +3 -3
  18. data/lib/llm/providers/gemini/error_handler.rb +34 -12
  19. data/lib/llm/providers/gemini/files.rb +19 -14
  20. data/lib/llm/providers/gemini/images.rb +4 -3
  21. data/lib/llm/providers/gemini/models.rb +4 -3
  22. data/lib/llm/providers/gemini.rb +9 -7
  23. data/lib/llm/providers/llamacpp.rb +3 -3
  24. data/lib/llm/providers/ollama/error_handler.rb +28 -6
  25. data/lib/llm/providers/ollama/models.rb +4 -3
  26. data/lib/llm/providers/ollama.rb +9 -7
  27. data/lib/llm/providers/openai/audio.rb +10 -7
  28. data/lib/llm/providers/openai/error_handler.rb +41 -14
  29. data/lib/llm/providers/openai/files.rb +19 -14
  30. data/lib/llm/providers/openai/images.rb +10 -7
  31. data/lib/llm/providers/openai/models.rb +4 -3
  32. data/lib/llm/providers/openai/moderations.rb +4 -3
  33. data/lib/llm/providers/openai/responses.rb +10 -7
  34. data/lib/llm/providers/openai/vector_stores.rb +34 -23
  35. data/lib/llm/providers/openai.rb +9 -7
  36. data/lib/llm/providers/xai.rb +3 -3
  37. data/lib/llm/providers/zai.rb +2 -2
  38. data/lib/llm/schema/object.rb +4 -4
  39. data/lib/llm/schema.rb +16 -2
  40. data/lib/llm/server_tool.rb +3 -3
  41. data/lib/llm/session/deserializer.rb +36 -0
  42. data/lib/llm/session.rb +3 -0
  43. data/lib/llm/tracer/logger.rb +192 -0
  44. data/lib/llm/tracer/null.rb +49 -0
  45. data/lib/llm/tracer/telemetry.rb +255 -0
  46. data/lib/llm/tracer.rb +134 -0
  47. data/lib/llm/version.rb +1 -1
  48. data/lib/llm.rb +4 -3
  49. data/llm.gemspec +6 -3
  50. metadata +41 -5
  51. data/lib/llm/builder.rb +0 -79
data/lib/llm/tracer.rb ADDED
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # The {LLM::Tracer LLM::Tracer} is the superclass of all
6
+ # LLM tracers. It can be helpful for implementing instrumentation
7
+ # and hooking into the lifecycle of an LLM request. See
8
+ # {LLM::Tracer::Telemetry LLM::Tracer::Telemetry}, and
9
+ # {LLM::Tracer::Logger LLM::Tracer::Logger} for example
10
+ # tracer implementations.
11
+ class Tracer
12
+ require_relative "tracer/logger"
13
+ require_relative "tracer/telemetry"
14
+ require_relative "tracer/null"
15
+
16
+ ##
17
+ # @param [LLM::Provider] provider
18
+ # A provider
19
+ # @param [Hash] options
20
+ # A hash of options
21
+ def initialize(provider, options = {})
22
+ @provider = provider
23
+ @options = {}
24
+ end
25
+
26
+ ##
27
+ # Called before an LLM provider request is executed.
28
+ # @param [String] operation
29
+ # @param [String] model
30
+ # @return [void]
31
+ def on_request_start(operation:, model: nil)
32
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
33
+ end
34
+
35
+ ##
36
+ # Called after an LLM provider request succeeds.
37
+ # @param [String] operation
38
+ # @param [String] model
39
+ # @param [LLM::Response] res
40
+ # @param [Object, nil] span
41
+ # @return [void]
42
+ def on_request_finish(operation:, res:, model: nil, span: nil)
43
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
44
+ end
45
+
46
+ ##
47
+ # Called when an LLM provider request fails.
48
+ # @param [LLM::Error] ex
49
+ # @param [Object, nil] span
50
+ # @return [void]
51
+ def on_request_error(ex:, span:)
52
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
53
+ end
54
+
55
+ ##
56
+ # Called before a local tool/function executes.
57
+ # @param [String] id
58
+ # The tool call ID assigned by the model/provider
59
+ # @param [String] name
60
+ # The tool (function) name.
61
+ # @param [Hash] arguments
62
+ # The parsed tool arguments.
63
+ # @param [String] model
64
+ # The model name
65
+ # @return [void]
66
+ def on_tool_start(id:, name:, arguments:, model:)
67
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
68
+ end
69
+
70
+ ##
71
+ # Called after a local tool/function succeeds.
72
+ # @param [LLM::Function::Return] result
73
+ # The tool return object.
74
+ # @param [Object, nil] span
75
+ # The span/context object returned by {#on_tool_start}.
76
+ # @return [void]
77
+ def on_tool_finish(result:, span:)
78
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
79
+ end
80
+
81
+ ##
82
+ # Called when a local tool/function raises.
83
+ # @param [Exception] ex
84
+ # The raised error.
85
+ # @param [Object, nil] span
86
+ # The span/context object returned by {#on_tool_start}.
87
+ # @return [void]
88
+ def on_tool_error(ex:, span:)
89
+ raise NotImplementedError, "#{self.class} does not implement '#{__method__}'"
90
+ end
91
+
92
+ ##
93
+ # @return [String]
94
+ def inspect
95
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} @provider=#{@provider.class} @tracer=#{@tracer.inspect}>"
96
+ end
97
+
98
+ ##
99
+ # @return [Array]
100
+ def spans
101
+ []
102
+ end
103
+
104
+ ##
105
+ # Flush the tracer
106
+ # @note
107
+ # This method is only implemented by the {LLM::Tracer::Telemetry} tracer.
108
+ # It is a noop for other tracers.
109
+ # @return [nil]
110
+ def flush!
111
+ nil
112
+ end
113
+
114
+ private
115
+
116
+ ##
117
+ # @return [String]
118
+ def provider_name
119
+ @provider.class.name.split("::").last.downcase
120
+ end
121
+
122
+ ##
123
+ # @return [String]
124
+ def provider_host
125
+ @provider.instance_variable_get(:@host)
126
+ end
127
+
128
+ ##
129
+ # @return [String]
130
+ def provider_port
131
+ @provider.instance_variable_get(:@port)
132
+ end
133
+ end
134
+ end
data/lib/llm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LLM
4
- VERSION = "4.1.0"
4
+ VERSION = "4.3.0"
5
5
  end
data/lib/llm.rb CHANGED
@@ -3,10 +3,11 @@
3
3
  module LLM
4
4
  require "stringio"
5
5
  require_relative "llm/json_adapter"
6
+ require_relative "llm/tracer"
6
7
  require_relative "llm/error"
7
8
  require_relative "llm/contract"
8
9
  require_relative "llm/usage"
9
- require_relative "llm/builder"
10
+ require_relative "llm/prompt"
10
11
  require_relative "llm/schema"
11
12
  require_relative "llm/object"
12
13
  require_relative "llm/version"
@@ -17,7 +18,7 @@ module LLM
17
18
  require_relative "llm/multipart"
18
19
  require_relative "llm/file"
19
20
  require_relative "llm/provider"
20
- require_relative "llm/bot"
21
+ require_relative "llm/session"
21
22
  require_relative "llm/agent"
22
23
  require_relative "llm/buffer"
23
24
  require_relative "llm/function"
@@ -35,7 +36,7 @@ module LLM
35
36
  ##
36
37
  # Returns the JSON adapter used by the library
37
38
  # @return [Class]
38
- # Returns a class that responds to +dump+ and +load+
39
+ # Returns a class that responds to `dump` and `load`
39
40
  def json
40
41
  @json ||= JSONAdapter::JSON
41
42
  end
data/llm.gemspec CHANGED
@@ -16,12 +16,13 @@ Gem::Specification.new do |spec|
16
16
  SUMMARY
17
17
 
18
18
  spec.description = spec.summary
19
- spec.homepage = "https://github.com/llmrb/llm"
20
19
  spec.license = "0BSD"
21
20
  spec.required_ruby_version = ">= 3.2.0"
22
21
 
23
- spec.metadata["homepage_uri"] = spec.homepage
24
- spec.metadata["source_code_uri"] = "https://github.com/llmrb/llm"
22
+ spec.homepage = "https://github.com/llmrb/llm.rb"
23
+ spec.metadata["homepage_uri"] = "https://github.com/llmrb/llm.rb"
24
+ spec.metadata["source_code_uri"] = "https://github.com/llmrb/llm.rb"
25
+ spec.metadata["documentation_uri"] = "https://0x1eef.github.io/x/llm.rb"
25
26
 
26
27
  spec.files = Dir[
27
28
  "README.md", "LICENSE",
@@ -41,4 +42,6 @@ Gem::Specification.new do |spec|
41
42
  spec.add_development_dependency "vcr", "~> 6.0"
42
43
  spec.add_development_dependency "dotenv", "~> 2.8"
43
44
  spec.add_development_dependency "net-http-persistent", "~> 4.0"
45
+ spec.add_development_dependency "opentelemetry-sdk", "~> 1.10"
46
+ spec.add_development_dependency "logger", "~> 1.7"
44
47
  end
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: 4.1.0
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antar Azri
@@ -164,6 +164,34 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '4.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: opentelemetry-sdk
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.10'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.10'
181
+ - !ruby/object:Gem::Dependency
182
+ name: logger
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '1.7'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '1.7'
167
195
  description: llm.rb is a zero-dependency Ruby toolkit for Large Language Models that
168
196
  includes OpenAI, Gemini, Anthropic, xAI (grok), zAI, DeepSeek, Ollama, and LlamaCpp.
169
197
  The toolkit includes full support for chat, streaming, tool calling, audio, images,
@@ -181,7 +209,6 @@ files:
181
209
  - lib/llm/agent.rb
182
210
  - lib/llm/bot.rb
183
211
  - lib/llm/buffer.rb
184
- - lib/llm/builder.rb
185
212
  - lib/llm/client.rb
186
213
  - lib/llm/contract.rb
187
214
  - lib/llm/contract/completion.rb
@@ -192,6 +219,7 @@ files:
192
219
  - lib/llm/eventstream/parser.rb
193
220
  - lib/llm/file.rb
194
221
  - lib/llm/function.rb
222
+ - lib/llm/function/tracing.rb
195
223
  - lib/llm/json_adapter.rb
196
224
  - lib/llm/message.rb
197
225
  - lib/llm/mime.rb
@@ -200,6 +228,7 @@ files:
200
228
  - lib/llm/object.rb
201
229
  - lib/llm/object/builder.rb
202
230
  - lib/llm/object/kernel.rb
231
+ - lib/llm/prompt.rb
203
232
  - lib/llm/provider.rb
204
233
  - lib/llm/providers/anthropic.rb
205
234
  - lib/llm/providers/anthropic/error_handler.rb
@@ -283,18 +312,25 @@ files:
283
312
  - lib/llm/schema/string.rb
284
313
  - lib/llm/schema/version.rb
285
314
  - lib/llm/server_tool.rb
315
+ - lib/llm/session.rb
316
+ - lib/llm/session/deserializer.rb
286
317
  - lib/llm/tool.rb
287
318
  - lib/llm/tool/param.rb
319
+ - lib/llm/tracer.rb
320
+ - lib/llm/tracer/logger.rb
321
+ - lib/llm/tracer/null.rb
322
+ - lib/llm/tracer/telemetry.rb
288
323
  - lib/llm/usage.rb
289
324
  - lib/llm/utils.rb
290
325
  - lib/llm/version.rb
291
326
  - llm.gemspec
292
- homepage: https://github.com/llmrb/llm
327
+ homepage: https://github.com/llmrb/llm.rb
293
328
  licenses:
294
329
  - 0BSD
295
330
  metadata:
296
- homepage_uri: https://github.com/llmrb/llm
297
- source_code_uri: https://github.com/llmrb/llm
331
+ homepage_uri: https://github.com/llmrb/llm.rb
332
+ source_code_uri: https://github.com/llmrb/llm.rb
333
+ documentation_uri: https://0x1eef.github.io/x/llm.rb
298
334
  rdoc_options: []
299
335
  require_paths:
300
336
  - lib
data/lib/llm/builder.rb DELETED
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- ##
4
- # The {LLM::Builder LLM::Builder} class can build a collection
5
- # of messages that can be sent in a single request.
6
- #
7
- # @note
8
- # This API is not meant to be used directly.
9
- #
10
- # @example
11
- # llm = LLM.openai(key: ENV["KEY"])
12
- # bot = LLM::Bot.new(llm)
13
- # prompt = bot.build_prompt do
14
- # it.system "Your task is to assist the user"
15
- # it.user "Hello. Can you assist me?"
16
- # end
17
- # res = bot.chat(prompt)
18
- class LLM::Builder
19
- ##
20
- # @param [Proc] evaluator
21
- # The evaluator
22
- def initialize(provider, &evaluator)
23
- @provider = provider
24
- @buffer = []
25
- @evaluator = evaluator
26
- end
27
-
28
- ##
29
- # @return [void]
30
- def call
31
- @evaluator.call(self)
32
- end
33
-
34
- ##
35
- # @param [String] content
36
- # The message
37
- # @param [Symbol] role
38
- # The role (eg user, system)
39
- # @return [void]
40
- def chat(content, role: @provider.user_role)
41
- role = case role.to_sym
42
- when :system then @provider.system_role
43
- when :user then @provider.user_role
44
- when :developer then @provider.developer_role
45
- else role
46
- end
47
- @buffer << LLM::Message.new(role, content)
48
- end
49
-
50
- ##
51
- # @param [String] content
52
- # The message content
53
- # @return [void]
54
- def user(content)
55
- chat(content, role: @provider.user_role)
56
- end
57
-
58
- ##
59
- # @param [String] content
60
- # The message content
61
- # @return [void]
62
- def system(content)
63
- chat(content, role: @provider.system_role)
64
- end
65
-
66
- ##
67
- # @param [String] content
68
- # The message content
69
- # @return [void]
70
- def developer(content)
71
- chat(content, role: @provider.developer_role)
72
- end
73
-
74
- ##
75
- # @return [Array]
76
- def to_a
77
- @buffer.dup
78
- end
79
- end