llm.rb 4.10.0 → 4.11.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +152 -0
  3. data/README.md +157 -36
  4. data/data/anthropic.json +209 -242
  5. data/data/deepseek.json +15 -15
  6. data/data/google.json +553 -403
  7. data/data/openai.json +740 -535
  8. data/data/xai.json +250 -253
  9. data/data/zai.json +157 -90
  10. data/lib/llm/context/deserializer.rb +2 -1
  11. data/lib/llm/context.rb +58 -2
  12. data/lib/llm/contract/completion.rb +7 -0
  13. data/lib/llm/error.rb +4 -0
  14. data/lib/llm/eventhandler.rb +7 -0
  15. data/lib/llm/function/registry.rb +106 -0
  16. data/lib/llm/function/task.rb +39 -0
  17. data/lib/llm/function.rb +12 -7
  18. data/lib/llm/mcp/transport/http.rb +40 -6
  19. data/lib/llm/mcp/transport/stdio.rb +7 -0
  20. data/lib/llm/mcp.rb +54 -24
  21. data/lib/llm/message.rb +9 -2
  22. data/lib/llm/provider.rb +10 -0
  23. data/lib/llm/providers/anthropic/response_adapter/completion.rb +6 -0
  24. data/lib/llm/providers/anthropic/stream_parser.rb +37 -4
  25. data/lib/llm/providers/anthropic.rb +1 -1
  26. data/lib/llm/providers/google/response_adapter/completion.rb +12 -5
  27. data/lib/llm/providers/google/stream_parser.rb +54 -11
  28. data/lib/llm/providers/google/utils.rb +30 -0
  29. data/lib/llm/providers/google.rb +2 -0
  30. data/lib/llm/providers/ollama/response_adapter/completion.rb +6 -0
  31. data/lib/llm/providers/ollama/stream_parser.rb +10 -4
  32. data/lib/llm/providers/ollama.rb +1 -1
  33. data/lib/llm/providers/openai/response_adapter/completion.rb +7 -0
  34. data/lib/llm/providers/openai/response_adapter/responds.rb +84 -10
  35. data/lib/llm/providers/openai/responses/stream_parser.rb +63 -4
  36. data/lib/llm/providers/openai/responses.rb +1 -1
  37. data/lib/llm/providers/openai/stream_parser.rb +68 -4
  38. data/lib/llm/providers/openai.rb +1 -1
  39. data/lib/llm/stream/queue.rb +51 -0
  40. data/lib/llm/stream.rb +102 -0
  41. data/lib/llm/tool.rb +50 -45
  42. data/lib/llm/version.rb +1 -1
  43. data/lib/llm.rb +3 -2
  44. data/llm.gemspec +2 -2
  45. metadata +7 -1
data/lib/llm/tool.rb CHANGED
@@ -20,6 +20,7 @@
20
20
  class LLM::Tool
21
21
  require_relative "tool/param"
22
22
  extend LLM::Tool::Param
23
+ extend LLM::Function::Registry
23
24
 
24
25
  types = [
25
26
  :Leaf, :String, :Enum,
@@ -39,58 +40,51 @@ class LLM::Tool
39
40
  # @return [Class<LLM::Tool>]
40
41
  # Returns a subclass of LLM::Tool
41
42
  def self.mcp(mcp, tool)
42
- klass = Class.new(LLM::Tool) do
43
- name tool["name"]
44
- description tool["description"]
45
- params { tool["inputSchema"] || {type: "object", properties: {}} }
46
-
47
- define_singleton_method(:inspect) do
48
- "<LLM::Tool:0x#{object_id.to_s(16)} name=#{tool["name"]} (mcp)>"
49
- end
50
- singleton_class.alias_method :to_s, :inspect
51
-
52
- define_singleton_method(:mcp?) do
53
- true
54
- end
55
-
56
- define_method(:call) do |**args|
57
- mcp.call_tool(tool["name"], args)
58
- end
59
- end
60
- unregister(klass)
61
- end
62
-
63
- ##
64
- # Returns all subclasses of LLM::Tool
65
- # @note
66
- # This method excludes tools who haven't defined a name
67
- # as well as tools defined via MCP.
68
- # @return [Array<LLM::Tool>]
69
- def self.registry
70
43
  lock do
71
- @registry.select(&:name)
44
+ @mcp = true
45
+ klass = Class.new(LLM::Tool) do
46
+ name tool["name"]
47
+ description tool["description"]
48
+ params { tool["inputSchema"] || {type: "object", properties: {}} }
49
+
50
+ define_singleton_method(:inspect) do
51
+ "<LLM::Tool:0x#{object_id.to_s(16)} name=#{tool["name"]} (mcp)>"
52
+ end
53
+ singleton_class.alias_method :to_s, :inspect
54
+
55
+ define_singleton_method(:mcp?) do
56
+ true
57
+ end
58
+
59
+ define_method(:call) do |**args|
60
+ mcp.call_tool(tool["name"], args)
61
+ end
62
+ end
63
+ @mcp = false
64
+ register(klass)
65
+ klass
66
+ ensure
67
+ @mcp = false
72
68
  end
73
69
  end
74
- @registry = []
75
70
 
76
71
  ##
77
72
  # Clear the registry
78
73
  # @return [void]
79
74
  def self.clear_registry!
80
75
  lock do
81
- @registry.clear
82
- nil
76
+ @__registry.each_value { LLM::Function.unregister(_1.function) }
77
+ super
83
78
  end
84
79
  end
85
80
 
86
81
  ##
87
- # Register a tool in the registry
82
+ # Registers a tool and its function.
88
83
  # @param [LLM::Tool] tool
89
84
  # @api private
90
85
  def self.register(tool)
91
- lock do
92
- @registry << tool
93
- end
86
+ super
87
+ LLM::Function.register(tool.function)
94
88
  end
95
89
 
96
90
  ##
@@ -99,7 +93,9 @@ class LLM::Tool
99
93
  # @api private
100
94
  def self.unregister(tool)
101
95
  lock do
102
- @registry.delete(tool)
96
+ LLM::Function.unregister(tool.function)
97
+ super
98
+ tool
103
99
  end
104
100
  end
105
101
 
@@ -111,7 +107,7 @@ class LLM::Tool
111
107
  LLM.lock(:inherited) do
112
108
  tool.instance_eval { @__monitor ||= Monitor.new }
113
109
  tool.function.register(tool)
114
- LLM::Tool.register(tool)
110
+ LLM::Tool.register(tool) unless lock { @mcp }
115
111
  end
116
112
  end
117
113
 
@@ -125,6 +121,22 @@ class LLM::Tool
125
121
  end
126
122
  end
127
123
 
124
+ ##
125
+ # Returns all registered tool classes with definitions.
126
+ # @return [Array<Class<LLM::Tool>>]
127
+ def self.registry
128
+ super.select(&:name)
129
+ end
130
+
131
+ ##
132
+ # Finds a registered tool by name.
133
+ # @param [String] name
134
+ # @return [Class<LLM::Tool>]
135
+ # @raise [LLM::NoSuchToolError]
136
+ def self.find_by_name!(name)
137
+ find_by_name(name) || raise(LLM::NoSuchToolError, "no such tool #{name.inspect}")
138
+ end
139
+
128
140
  ##
129
141
  # Returns (or sets) the tool description
130
142
  # @param [String, nil] desc The tool description
@@ -153,13 +165,6 @@ class LLM::Tool
153
165
  end
154
166
  end
155
167
 
156
- ##
157
- # @api private
158
- def self.lock(&)
159
- @__monitor.synchronize(&)
160
- end
161
- @__monitor = Monitor.new
162
-
163
168
  ##
164
169
  # Returns true if the tool is an MCP tool
165
170
  # @return [Boolean]
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.10.0"
4
+ VERSION = "4.11.0"
5
5
  end
data/lib/llm.rb CHANGED
@@ -20,6 +20,7 @@ module LLM
20
20
  require_relative "llm/mime"
21
21
  require_relative "llm/multipart"
22
22
  require_relative "llm/file"
23
+ require_relative "llm/stream"
23
24
  require_relative "llm/provider"
24
25
  require_relative "llm/context"
25
26
  require_relative "llm/agent"
@@ -29,10 +30,11 @@ module LLM
29
30
  require_relative "llm/eventhandler"
30
31
  require_relative "llm/tool"
31
32
  require_relative "llm/server_tool"
33
+ require_relative "llm/mcp"
32
34
 
33
35
  ##
34
36
  # Thread-safe monitors for different contexts
35
- @monitors = {require: Monitor.new, clients: Monitor.new, inherited: Monitor.new, registry: Monitor.new}
37
+ @monitors = {require: Monitor.new, clients: Monitor.new, inherited: Monitor.new, registry: Monitor.new, mcp: Monitor.new}
36
38
 
37
39
  ##
38
40
  # Model registry
@@ -161,7 +163,6 @@ module LLM
161
163
  # The working directory for the MCP process
162
164
  # @return [LLM::MCP]
163
165
  def mcp(llm = nil, **)
164
- lock(:require) { require_relative "llm/mcp" unless defined?(LLM::MCP) }
165
166
  LLM::MCP.new(llm, **)
166
167
  end
167
168
 
data/llm.gemspec CHANGED
@@ -63,7 +63,7 @@ Gem::Specification.new do |spec|
63
63
  spec.files = Dir[
64
64
  "README.md", "LICENSE",
65
65
  "lib/*.rb", "lib/**/*.rb",
66
- "data/*.json",
66
+ "data/*.json", "CHANGELOG.md",
67
67
  "llm.gemspec"
68
68
  ]
69
69
  spec.require_paths = ["lib"]
@@ -81,4 +81,4 @@ Gem::Specification.new do |spec|
81
81
  spec.add_development_dependency "net-http-persistent", "~> 4.0"
82
82
  spec.add_development_dependency "opentelemetry-sdk", "~> 1.10"
83
83
  spec.add_development_dependency "logger", "~> 1.7"
84
- end
84
+ 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.10.0
4
+ version: 4.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antar Azri
@@ -235,6 +235,7 @@ executables: []
235
235
  extensions: []
236
236
  extra_rdoc_files: []
237
237
  files:
238
+ - CHANGELOG.md
238
239
  - LICENSE
239
240
  - README.md
240
241
  - data/anthropic.json
@@ -262,6 +263,8 @@ files:
262
263
  - lib/llm/function.rb
263
264
  - lib/llm/function/array.rb
264
265
  - lib/llm/function/fiber_group.rb
266
+ - lib/llm/function/registry.rb
267
+ - lib/llm/function/task.rb
265
268
  - lib/llm/function/task_group.rb
266
269
  - lib/llm/function/thread_group.rb
267
270
  - lib/llm/function/tracing.rb
@@ -317,6 +320,7 @@ files:
317
320
  - lib/llm/providers/google/response_adapter/models.rb
318
321
  - lib/llm/providers/google/response_adapter/web_search.rb
319
322
  - lib/llm/providers/google/stream_parser.rb
323
+ - lib/llm/providers/google/utils.rb
320
324
  - lib/llm/providers/llamacpp.rb
321
325
  - lib/llm/providers/ollama.rb
322
326
  - lib/llm/providers/ollama/error_handler.rb
@@ -376,6 +380,8 @@ files:
376
380
  - lib/llm/schema/version.rb
377
381
  - lib/llm/server_tool.rb
378
382
  - lib/llm/session.rb
383
+ - lib/llm/stream.rb
384
+ - lib/llm/stream/queue.rb
379
385
  - lib/llm/tool.rb
380
386
  - lib/llm/tool/param.rb
381
387
  - lib/llm/tracer.rb