llm.rb 4.9.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +152 -0
  3. data/README.md +178 -31
  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/event_handler.rb +66 -0
  19. data/lib/llm/mcp/transport/http.rb +156 -0
  20. data/lib/llm/mcp/transport/stdio.rb +7 -0
  21. data/lib/llm/mcp.rb +74 -30
  22. data/lib/llm/message.rb +9 -2
  23. data/lib/llm/provider.rb +10 -0
  24. data/lib/llm/providers/anthropic/response_adapter/completion.rb +6 -0
  25. data/lib/llm/providers/anthropic/stream_parser.rb +37 -4
  26. data/lib/llm/providers/anthropic.rb +1 -1
  27. data/lib/llm/providers/google/response_adapter/completion.rb +12 -5
  28. data/lib/llm/providers/google/stream_parser.rb +54 -11
  29. data/lib/llm/providers/google/utils.rb +30 -0
  30. data/lib/llm/providers/google.rb +2 -0
  31. data/lib/llm/providers/ollama/response_adapter/completion.rb +6 -0
  32. data/lib/llm/providers/ollama/stream_parser.rb +10 -4
  33. data/lib/llm/providers/ollama.rb +1 -1
  34. data/lib/llm/providers/openai/response_adapter/completion.rb +7 -0
  35. data/lib/llm/providers/openai/response_adapter/responds.rb +84 -10
  36. data/lib/llm/providers/openai/responses/stream_parser.rb +63 -4
  37. data/lib/llm/providers/openai/responses.rb +1 -1
  38. data/lib/llm/providers/openai/stream_parser.rb +68 -4
  39. data/lib/llm/providers/openai.rb +1 -1
  40. data/lib/llm/schema/all_of.rb +31 -0
  41. data/lib/llm/schema/any_of.rb +31 -0
  42. data/lib/llm/schema/one_of.rb +31 -0
  43. data/lib/llm/schema/parser.rb +36 -0
  44. data/lib/llm/schema.rb +45 -8
  45. data/lib/llm/stream/queue.rb +51 -0
  46. data/lib/llm/stream.rb +102 -0
  47. data/lib/llm/tool.rb +53 -47
  48. data/lib/llm/version.rb +1 -1
  49. data/lib/llm.rb +3 -2
  50. data/llm.gemspec +2 -2
  51. metadata +12 -1
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LLM::Schema
4
+ ##
5
+ # The {LLM::Schema::AnyOf LLM::Schema::AnyOf} class represents an
6
+ # anyOf union in a JSON schema. It is a subclass of
7
+ # {LLM::Schema::Leaf LLM::Schema::Leaf}.
8
+ class AnyOf < Leaf
9
+ ##
10
+ # Returns an anyOf union for the given types.
11
+ # @return [LLM::Schema::AnyOf]
12
+ def self.[](*types)
13
+ schema = LLM::Schema.new
14
+ new(types.map { LLM::Schema::Utils.resolve(schema, _1) })
15
+ end
16
+
17
+ ##
18
+ # @param [Array<LLM::Schema::Leaf>] values
19
+ # The values allowed by the union
20
+ # @return [LLM::Schema::AnyOf]
21
+ def initialize(values)
22
+ @values = values
23
+ end
24
+
25
+ ##
26
+ # @return [Hash]
27
+ def to_h
28
+ super.merge!(anyOf: @values)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LLM::Schema
4
+ ##
5
+ # The {LLM::Schema::OneOf LLM::Schema::OneOf} class represents an
6
+ # oneOf union in a JSON schema. It is a subclass of
7
+ # {LLM::Schema::Leaf LLM::Schema::Leaf}.
8
+ class OneOf < Leaf
9
+ ##
10
+ # Returns a oneOf union for the given types.
11
+ # @return [LLM::Schema::OneOf]
12
+ def self.[](*types)
13
+ schema = LLM::Schema.new
14
+ new(types.map { LLM::Schema::Utils.resolve(schema, _1) })
15
+ end
16
+
17
+ ##
18
+ # @param [Array<LLM::Schema::Leaf>] values
19
+ # The values allowed by the union
20
+ # @return [LLM::Schema::OneOf]
21
+ def initialize(values)
22
+ @values = values
23
+ end
24
+
25
+ ##
26
+ # @return [Hash]
27
+ def to_h
28
+ super.merge!(oneOf: @values)
29
+ end
30
+ end
31
+ end
@@ -8,6 +8,8 @@ class LLM::Schema
8
8
  # external JSON schema definitions into the schema objects used
9
9
  # throughout llm.rb.
10
10
  module Parser
11
+ METADATA_KEYS = %w[description default enum const].freeze
12
+
11
13
  ##
12
14
  # Parses a JSON schema into an {LLM::Schema::Leaf}.
13
15
  # @param [Hash] schema
@@ -27,6 +29,8 @@ class LLM::Schema
27
29
  when "number" then apply(parse_number(schema), schema)
28
30
  when "boolean" then apply(schema().boolean, schema)
29
31
  when "null" then apply(schema().null, schema)
32
+ when ::Array then apply(schema().any_of(*schema["type"].map { parse(schema.except("type", *METADATA_KEYS).merge("type" => _1), root) }), schema.except("type"))
33
+ when nil then parse_union(schema, root)
30
34
  else raise TypeError, "unsupported schema type #{schema["type"].inspect}"
31
35
  end
32
36
  end
@@ -50,6 +54,14 @@ class LLM::Schema
50
54
  schema().array(items)
51
55
  end
52
56
 
57
+ def parse_union(schema, root)
58
+ return apply(schema().any_of(*schema["anyOf"].map { parse(_1, root) }), schema) if schema.key?("anyOf")
59
+ return apply(schema().one_of(*schema["oneOf"].map { parse(_1, root) }), schema) if schema.key?("oneOf")
60
+ return apply(schema().all_of(*schema["allOf"].map { parse(_1, root) }), schema) if schema.key?("allOf")
61
+ return parse(infer_type(schema), root) if infer_type(schema)
62
+ raise TypeError, "unsupported schema type #{schema["type"].inspect}"
63
+ end
64
+
53
65
  def parse_string(schema)
54
66
  leaf = schema().string
55
67
  leaf.min(schema["minLength"]) if schema.key?("minLength")
@@ -105,5 +117,29 @@ class LLM::Schema
105
117
  rescue KeyError
106
118
  raise TypeError, "unresolvable schema ref #{ref.inspect}"
107
119
  end
120
+
121
+ def infer_type(schema)
122
+ if schema.key?("const")
123
+ schema.merge("type" => type_of(schema["const"]))
124
+ elsif schema.key?("enum")
125
+ type = type_of(schema["enum"].first)
126
+ return unless type && schema["enum"].all? { type_of(_1) == type }
127
+ schema.merge("type" => type)
128
+ elsif schema.key?("default")
129
+ schema.merge("type" => type_of(schema["default"]))
130
+ end
131
+ end
132
+
133
+ def type_of(value)
134
+ case value
135
+ when ::Hash then "object"
136
+ when ::Array then "array"
137
+ when ::String then "string"
138
+ when ::Integer then "integer"
139
+ when ::Float then "number"
140
+ when ::TrueClass, ::FalseClass then "boolean"
141
+ when ::NilClass then "null"
142
+ end
143
+ end
108
144
  end
109
145
  end
data/lib/llm/schema.rb CHANGED
@@ -35,6 +35,9 @@ class LLM::Schema
35
35
  require_relative "schema/leaf"
36
36
  require_relative "schema/object"
37
37
  require_relative "schema/array"
38
+ require_relative "schema/all_of"
39
+ require_relative "schema/any_of"
40
+ require_relative "schema/one_of"
38
41
  require_relative "schema/string"
39
42
  require_relative "schema/enum"
40
43
  require_relative "schema/number"
@@ -45,6 +48,23 @@ class LLM::Schema
45
48
  @__monitor = Monitor.new
46
49
  extend LLM::Schema::Parser
47
50
 
51
+ ##
52
+ # @api private
53
+ module Utils
54
+ extend self
55
+
56
+ def resolve(schema, type)
57
+ if LLM::Schema::Leaf === type
58
+ type
59
+ elsif Class === type && type.respond_to?(:object)
60
+ type.object
61
+ else
62
+ target = type.name.split("::").last.downcase
63
+ schema.public_send(target)
64
+ end
65
+ end
66
+ end
67
+
48
68
  ##
49
69
  # Configures a monitor for a subclass
50
70
  # @return [void]
@@ -65,14 +85,7 @@ class LLM::Schema
65
85
  # A hash of options
66
86
  def self.property(name, type, description, options = {})
67
87
  lock do
68
- if LLM::Schema::Leaf === type
69
- prop = type
70
- elsif Class === type && type.respond_to?(:object)
71
- prop = type.object
72
- else
73
- target = type.name.split("::").last.downcase
74
- prop = schema.public_send(target)
75
- end
88
+ prop = Utils.resolve(schema, type)
76
89
  options = {description:}.merge(options)
77
90
  options.each { (_2 == true) ? prop.public_send(_1) : prop.public_send(_1, *_2) }
78
91
  object[name] = prop
@@ -120,6 +133,30 @@ class LLM::Schema
120
133
  Array.new(*items)
121
134
  end
122
135
 
136
+ ##
137
+ # Returns an anyOf union
138
+ # @param [Array<LLM::Schema::Leaf>] values The union values
139
+ # @return [LLM::Schema::AnyOf]
140
+ def any_of(*values)
141
+ AnyOf.new(values)
142
+ end
143
+
144
+ ##
145
+ # Returns an allOf union
146
+ # @param [Array<LLM::Schema::Leaf>] values The union values
147
+ # @return [LLM::Schema::AllOf]
148
+ def all_of(*values)
149
+ AllOf.new(values)
150
+ end
151
+
152
+ ##
153
+ # Returns a oneOf union
154
+ # @param [Array<LLM::Schema::Leaf>] values The union values
155
+ # @return [LLM::Schema::OneOf]
156
+ def one_of(*values)
157
+ OneOf.new(values)
158
+ end
159
+
123
160
  ##
124
161
  # Returns a string
125
162
  # @return [LLM::Schema::String]
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LLM::Stream
4
+ ##
5
+ # A small queue for collecting streamed tool work. Values can be immediate
6
+ # {LLM::Function::Return} objects or concurrent handles returned by
7
+ # {LLM::Function#spawn}. Calling {#wait(strategy)} resolves queued work and
8
+ # returns an array of {LLM::Function::Return} values.
9
+ class Queue
10
+ ##
11
+ # @return [LLM::Stream::Queue]
12
+ def initialize
13
+ @items = []
14
+ end
15
+
16
+ ##
17
+ # Enqueue a function return or spawned task.
18
+ # @param [LLM::Function::Return, Thread, Async::Task, Fiber] item
19
+ # @return [LLM::Stream::Queue]
20
+ def <<(item)
21
+ @items << item
22
+ self
23
+ end
24
+
25
+ ##
26
+ # Returns true when the queue is empty.
27
+ # @return [Boolean]
28
+ def empty?
29
+ @items.empty?
30
+ end
31
+
32
+ ##
33
+ # Waits for queued work to finish and returns function results.
34
+ # @param [Symbol] strategy
35
+ # Controls concurrency strategy:
36
+ # - `:thread`: Use threads
37
+ # - `:task`: Use async tasks (requires async gem)
38
+ # - `:fiber`: Use raw fibers
39
+ # @return [Array<LLM::Function::Return>]
40
+ def wait(strategy)
41
+ returns, tasks = @items.shift(@items.length).partition { LLM::Function::Return === _1 }
42
+ returns.concat case strategy
43
+ when :thread then LLM::Function::ThreadGroup.new(tasks).wait
44
+ when :task then LLM::Function::TaskGroup.new(tasks).wait
45
+ when :fiber then LLM::Function::FiberGroup.new(tasks).wait
46
+ else raise ArgumentError, "Unknown strategy: #{strategy.inspect}. Expected :thread, :task, or :fiber"
47
+ end
48
+ end
49
+ alias_method :value, :wait
50
+ end
51
+ end
data/lib/llm/stream.rb ADDED
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LLM
4
+ ##
5
+ # The {LLM::Stream LLM::Stream} class provides the callback interface for
6
+ # streamed model output in llm.rb.
7
+ #
8
+ # A stream object can be an instance of {LLM::Stream LLM::Stream}, a
9
+ # subclass that overrides the callbacks it needs, or any other object that
10
+ # implements some or all of the same interface. {#queue} provides a small
11
+ # helper for collecting asynchronous tool work started from a callback, and
12
+ # {#tool_not_found} returns an in-band tool error when a streamed tool
13
+ # cannot be resolved.
14
+ #
15
+ # @note The `on_*` callbacks run inline with the streaming parser. They
16
+ # therefore block streaming progress and should generally return as
17
+ # quickly as possible.
18
+ #
19
+ # The most common callback is {#on_content}, which also maps to {#<<} for
20
+ # compatibility with `StringIO`-style objects. Providers may also call
21
+ # {#on_reasoning_content} and {#on_tool_call} when that data is available.
22
+ class Stream
23
+ require_relative "stream/queue"
24
+
25
+ ##
26
+ # Returns a lazily-initialized queue for tool results or spawned work.
27
+ # @return [LLM::Stream::Queue]
28
+ def queue
29
+ @queue ||= Queue.new
30
+ end
31
+
32
+ ##
33
+ # Waits for queued tool work to finish and returns function results.
34
+ # @param [Symbol] strategy
35
+ # The concurrency strategy to use
36
+ # @return [Array<LLM::Function::Return>]
37
+ def wait(strategy)
38
+ queue.wait(strategy)
39
+ end
40
+
41
+ # @group Public callbacks
42
+
43
+ ##
44
+ # Called when visible assistant output is streamed.
45
+ # @param [String] content
46
+ # A chunk of assistant-visible text.
47
+ # @return [nil]
48
+ def on_content(content)
49
+ nil
50
+ end
51
+ alias_method :<<, :on_content
52
+
53
+ ##
54
+ # Called when reasoning output is streamed separately from visible content.
55
+ # @param [String] content
56
+ # A chunk of reasoning text.
57
+ # @return [nil]
58
+ def on_reasoning_content(content)
59
+ nil
60
+ end
61
+
62
+ ##
63
+ # Called when a streamed tool call has been fully constructed.
64
+ # @note A stream implementation may start tool execution here, for
65
+ # example by pushing `tool.spawn(:thread)`, `tool.spawn(:fiber)`, or
66
+ # `tool.spawn(:task)` onto {#queue}. When a streamed tool cannot be
67
+ # resolved, `error` is passed as an {LLM::Function::Return}. It can be
68
+ # sent back to the model, allowing the tool-call path to recover and the
69
+ # session to continue. Tool resolution depends on
70
+ # {LLM::Function.registry}, which includes {LLM::Tool LLM::Tool}
71
+ # subclasses, including MCP tools, but not functions defined with
72
+ # {LLM.function}.
73
+ # @param [LLM::Function] tool
74
+ # The parsed tool call.
75
+ # @param [LLM::Function::Return, nil] error
76
+ # An in-band tool error for unresolved tool calls.
77
+ # @return [nil]
78
+ def on_tool_call(tool, error)
79
+ nil
80
+ end
81
+
82
+ # @endgroup
83
+
84
+ # @group Error handlers
85
+
86
+ ##
87
+ # Returns a function return describing a streamed tool that could not
88
+ # be resolved.
89
+ # @note This is mainly useful as a fallback from {#on_tool_call}. It
90
+ # should be uncommon in normal use, since streamed tool callbacks only
91
+ # run for tools already defined in the context.
92
+ # @param [LLM::Function] tool
93
+ # @return [LLM::Function::Return]
94
+ def tool_not_found(tool)
95
+ LLM::Function::Return.new(tool.id, tool.name, {
96
+ error: true, type: LLM::NoSuchToolError.name, message: "tool not found"
97
+ })
98
+ end
99
+
100
+ # @endgroup
101
+ end
102
+ end
data/lib/llm/tool.rb CHANGED
@@ -20,11 +20,13 @@
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
- :Leaf, :String, :Enum, :Array,
26
+ :Leaf, :String, :Enum,
27
+ :AllOf, :AnyOf, :OneOf,
26
28
  :Object, :Integer, :Number,
27
- :Boolean, :Null
29
+ :Array, :Boolean, :Null
28
30
  ]
29
31
  types.each do |constant|
30
32
  const_set constant, LLM::Schema.const_get(constant)
@@ -38,58 +40,51 @@ class LLM::Tool
38
40
  # @return [Class<LLM::Tool>]
39
41
  # Returns a subclass of LLM::Tool
40
42
  def self.mcp(mcp, tool)
41
- klass = Class.new(LLM::Tool) do
42
- name tool["name"]
43
- description tool["description"]
44
- params { tool["inputSchema"] || {type: "object", properties: {}} }
45
-
46
- define_singleton_method(:inspect) do
47
- "<LLM::Tool:0x#{object_id.to_s(16)} name=#{tool["name"]} (mcp)>"
48
- end
49
- singleton_class.alias_method :to_s, :inspect
50
-
51
- define_singleton_method(:mcp?) do
52
- true
53
- end
54
-
55
- define_method(:call) do |**args|
56
- mcp.call_tool(tool["name"], args)
57
- end
58
- end
59
- unregister(klass)
60
- end
61
-
62
- ##
63
- # Returns all subclasses of LLM::Tool
64
- # @note
65
- # This method excludes tools who haven't defined a name
66
- # as well as tools defined via MCP.
67
- # @return [Array<LLM::Tool>]
68
- def self.registry
69
43
  lock do
70
- @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
71
68
  end
72
69
  end
73
- @registry = []
74
70
 
75
71
  ##
76
72
  # Clear the registry
77
73
  # @return [void]
78
74
  def self.clear_registry!
79
75
  lock do
80
- @registry.clear
81
- nil
76
+ @__registry.each_value { LLM::Function.unregister(_1.function) }
77
+ super
82
78
  end
83
79
  end
84
80
 
85
81
  ##
86
- # Register a tool in the registry
82
+ # Registers a tool and its function.
87
83
  # @param [LLM::Tool] tool
88
84
  # @api private
89
85
  def self.register(tool)
90
- lock do
91
- @registry << tool
92
- end
86
+ super
87
+ LLM::Function.register(tool.function)
93
88
  end
94
89
 
95
90
  ##
@@ -98,7 +93,9 @@ class LLM::Tool
98
93
  # @api private
99
94
  def self.unregister(tool)
100
95
  lock do
101
- @registry.delete(tool)
96
+ LLM::Function.unregister(tool.function)
97
+ super
98
+ tool
102
99
  end
103
100
  end
104
101
 
@@ -110,7 +107,7 @@ class LLM::Tool
110
107
  LLM.lock(:inherited) do
111
108
  tool.instance_eval { @__monitor ||= Monitor.new }
112
109
  tool.function.register(tool)
113
- LLM::Tool.register(tool)
110
+ LLM::Tool.register(tool) unless lock { @mcp }
114
111
  end
115
112
  end
116
113
 
@@ -124,6 +121,22 @@ class LLM::Tool
124
121
  end
125
122
  end
126
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
+
127
140
  ##
128
141
  # Returns (or sets) the tool description
129
142
  # @param [String, nil] desc The tool description
@@ -152,13 +165,6 @@ class LLM::Tool
152
165
  end
153
166
  end
154
167
 
155
- ##
156
- # @api private
157
- def self.lock(&)
158
- @__monitor.synchronize(&)
159
- end
160
- @__monitor = Monitor.new
161
-
162
168
  ##
163
169
  # Returns true if the tool is an MCP tool
164
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.9.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.9.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
@@ -271,6 +274,8 @@ files:
271
274
  - lib/llm/mcp/error.rb
272
275
  - lib/llm/mcp/pipe.rb
273
276
  - lib/llm/mcp/rpc.rb
277
+ - lib/llm/mcp/transport/http.rb
278
+ - lib/llm/mcp/transport/http/event_handler.rb
274
279
  - lib/llm/mcp/transport/stdio.rb
275
280
  - lib/llm/message.rb
276
281
  - lib/llm/mime.rb
@@ -315,6 +320,7 @@ files:
315
320
  - lib/llm/providers/google/response_adapter/models.rb
316
321
  - lib/llm/providers/google/response_adapter/web_search.rb
317
322
  - lib/llm/providers/google/stream_parser.rb
323
+ - lib/llm/providers/google/utils.rb
318
324
  - lib/llm/providers/llamacpp.rb
319
325
  - lib/llm/providers/ollama.rb
320
326
  - lib/llm/providers/ollama/error_handler.rb
@@ -358,6 +364,8 @@ files:
358
364
  - lib/llm/registry.rb
359
365
  - lib/llm/response.rb
360
366
  - lib/llm/schema.rb
367
+ - lib/llm/schema/all_of.rb
368
+ - lib/llm/schema/any_of.rb
361
369
  - lib/llm/schema/array.rb
362
370
  - lib/llm/schema/boolean.rb
363
371
  - lib/llm/schema/enum.rb
@@ -366,11 +374,14 @@ files:
366
374
  - lib/llm/schema/null.rb
367
375
  - lib/llm/schema/number.rb
368
376
  - lib/llm/schema/object.rb
377
+ - lib/llm/schema/one_of.rb
369
378
  - lib/llm/schema/parser.rb
370
379
  - lib/llm/schema/string.rb
371
380
  - lib/llm/schema/version.rb
372
381
  - lib/llm/server_tool.rb
373
382
  - lib/llm/session.rb
383
+ - lib/llm/stream.rb
384
+ - lib/llm/stream/queue.rb
374
385
  - lib/llm/tool.rb
375
386
  - lib/llm/tool/param.rb
376
387
  - lib/llm/tracer.rb