llm.rb 9.0.0 → 11.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +182 -4
- data/README.md +194 -42
- data/data/anthropic.json +278 -258
- data/data/bedrock.json +1288 -1561
- data/data/deepseek.json +38 -38
- data/data/google.json +656 -579
- data/data/openai.json +860 -818
- data/data/xai.json +243 -552
- data/data/zai.json +168 -168
- data/lib/llm/a2a/card/capabilities.rb +41 -0
- data/lib/llm/a2a/card/interface.rb +34 -0
- data/lib/llm/a2a/card/provider.rb +27 -0
- data/lib/llm/a2a/card/skill.rb +68 -0
- data/lib/llm/a2a/card.rb +144 -0
- data/lib/llm/a2a/error.rb +49 -0
- data/lib/llm/a2a/notifications.rb +53 -0
- data/lib/llm/a2a/tasks.rb +55 -0
- data/lib/llm/a2a/transport/http.rb +131 -0
- data/lib/llm/a2a.rb +452 -0
- data/lib/llm/active_record/acts_as_agent.rb +20 -9
- data/lib/llm/active_record/acts_as_llm.rb +4 -4
- data/lib/llm/active_record.rb +1 -6
- data/lib/llm/agent.rb +96 -71
- data/lib/llm/buffer.rb +1 -2
- data/lib/llm/context.rb +77 -50
- data/lib/llm/file.rb +7 -0
- data/lib/llm/function/call_task.rb +46 -0
- data/lib/llm/function.rb +28 -2
- data/lib/llm/mcp/transport/http.rb +5 -18
- data/lib/llm/mcp/transport/stdio.rb +7 -0
- data/lib/llm/mcp.rb +20 -17
- data/lib/llm/message.rb +1 -1
- data/lib/llm/object/kernel.rb +1 -1
- data/lib/llm/provider.rb +9 -9
- data/lib/llm/providers/anthropic/stream_parser.rb +2 -2
- data/lib/llm/providers/bedrock/stream_parser.rb +2 -2
- data/lib/llm/providers/google/stream_parser.rb +2 -2
- data/lib/llm/providers/openai/responses/stream_parser.rb +2 -2
- data/lib/llm/providers/openai/stream_parser.rb +2 -2
- data/lib/llm/response.rb +1 -1
- data/lib/llm/schema.rb +11 -0
- data/lib/llm/sequel/agent.rb +19 -9
- data/lib/llm/sequel/plugin.rb +9 -13
- data/lib/llm/stream.rb +11 -36
- data/lib/llm/tool/param.rb +1 -8
- data/lib/llm/tool.rb +57 -27
- data/lib/llm/tracer.rb +1 -1
- data/lib/llm/transport/http.rb +1 -1
- data/lib/llm/transport/stream_decoder.rb +6 -3
- data/lib/llm/transport/utils.rb +35 -0
- data/lib/llm/transport.rb +1 -0
- data/lib/llm/utils.rb +73 -0
- data/lib/llm/version.rb +1 -1
- data/lib/llm.rb +24 -4
- data/llm.gemspec +16 -1
- metadata +29 -5
- data/lib/llm/bot.rb +0 -3
- data/lib/llm/mcp/transport/http/event_handler.rb +0 -68
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class LLM::Transport
|
|
4
|
+
##
|
|
5
|
+
# Shared utility methods for HTTP-backed transports.
|
|
6
|
+
#
|
|
7
|
+
# @api private
|
|
8
|
+
module Utils
|
|
9
|
+
extend self
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def resolve_transport(uri, transport, timeout)
|
|
13
|
+
return default_transport(uri, timeout) if transport.nil?
|
|
14
|
+
if Class === transport && transport <= LLM::Transport
|
|
15
|
+
transport.new(
|
|
16
|
+
host: uri.host,
|
|
17
|
+
port: uri.port,
|
|
18
|
+
timeout:,
|
|
19
|
+
ssl: uri.scheme == "https"
|
|
20
|
+
)
|
|
21
|
+
else
|
|
22
|
+
transport
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def default_transport(uri, timeout)
|
|
27
|
+
LLM::Transport::HTTP.new(
|
|
28
|
+
host: uri.host,
|
|
29
|
+
port: uri.port,
|
|
30
|
+
timeout:,
|
|
31
|
+
ssl: uri.scheme == "https"
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/llm/transport.rb
CHANGED
|
@@ -27,6 +27,7 @@ module LLM
|
|
|
27
27
|
# transport-specific classes.
|
|
28
28
|
class Transport
|
|
29
29
|
require_relative "transport/response"
|
|
30
|
+
require_relative "transport/utils"
|
|
30
31
|
require_relative "transport/stream_decoder"
|
|
31
32
|
require_relative "transport/http"
|
|
32
33
|
require_relative "transport/persistent_http"
|
data/lib/llm/utils.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LLM
|
|
4
|
+
##
|
|
5
|
+
# Shared utility methods used across the runtime.
|
|
6
|
+
module Utils
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Resolves a configured option against an object instance.
|
|
11
|
+
#
|
|
12
|
+
# Proc values are evaluated with `instance_exec`, symbol values are
|
|
13
|
+
# optionally sent to the object as method calls, hashes are duplicated,
|
|
14
|
+
# and all other values are returned as-is.
|
|
15
|
+
#
|
|
16
|
+
# @param [Object] obj
|
|
17
|
+
# @param [Object] option
|
|
18
|
+
# @param [Boolean] resolve_symbol
|
|
19
|
+
# @return [Object]
|
|
20
|
+
def resolve_option(obj, option, resolve_symbol: true)
|
|
21
|
+
case option
|
|
22
|
+
when Proc then obj.instance_exec(&option)
|
|
23
|
+
when Symbol then resolve_symbol ? obj.send(option) : option
|
|
24
|
+
when Hash then option.dup
|
|
25
|
+
else option
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Normalizes an HTTP API base path.
|
|
31
|
+
#
|
|
32
|
+
# Blank paths normalize to an empty string. Non-empty paths are
|
|
33
|
+
# prefixed with a leading slash and stripped of trailing slashes.
|
|
34
|
+
#
|
|
35
|
+
# @param [String, nil] path
|
|
36
|
+
# @return [String]
|
|
37
|
+
def normalize_base_path(path)
|
|
38
|
+
path = path.to_s.strip
|
|
39
|
+
return "" if path.empty? || path == "/"
|
|
40
|
+
path = "/#{path}" unless path.start_with?("/")
|
|
41
|
+
path.sub(%r{/+\z}, "")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Returns the Ruby module or class name for an object.
|
|
46
|
+
#
|
|
47
|
+
# This bypasses overridden `#name` implementations by binding
|
|
48
|
+
# {Module#name} directly.
|
|
49
|
+
#
|
|
50
|
+
# @param [Module] obj
|
|
51
|
+
# @return [String, nil]
|
|
52
|
+
def name_of(obj)
|
|
53
|
+
::Module.instance_method(:name).bind(obj).call
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Renders the class-and-object-id portion of an inspect string.
|
|
58
|
+
#
|
|
59
|
+
# This returns strings like `LLM::Tool:0x1234abcd`, which can be
|
|
60
|
+
# embedded into custom inspect output.
|
|
61
|
+
#
|
|
62
|
+
# @param [Object] obj
|
|
63
|
+
# @return [String]
|
|
64
|
+
def object_id(obj)
|
|
65
|
+
klass = if Class === obj
|
|
66
|
+
name_of(obj) || name_of(obj.superclass) || obj.class.name
|
|
67
|
+
else
|
|
68
|
+
obj.class.name || obj.class.to_s
|
|
69
|
+
end
|
|
70
|
+
"#{klass}:0x#{obj.object_id.to_s(16)}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/llm/version.rb
CHANGED
data/lib/llm.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module LLM
|
|
4
4
|
require "stringio"
|
|
5
|
+
require "securerandom"
|
|
5
6
|
require_relative "llm/json_adapter"
|
|
6
7
|
require_relative "llm/tracer"
|
|
7
8
|
require_relative "llm/error"
|
|
@@ -12,6 +13,7 @@ module LLM
|
|
|
12
13
|
require_relative "llm/prompt"
|
|
13
14
|
require_relative "llm/schema"
|
|
14
15
|
require_relative "llm/object"
|
|
16
|
+
require_relative "llm/utils"
|
|
15
17
|
require_relative "llm/model"
|
|
16
18
|
require_relative "llm/version"
|
|
17
19
|
require_relative "llm/message"
|
|
@@ -34,6 +36,7 @@ module LLM
|
|
|
34
36
|
require_relative "llm/skill"
|
|
35
37
|
require_relative "llm/server_tool"
|
|
36
38
|
require_relative "llm/mcp"
|
|
39
|
+
require_relative "llm/a2a"
|
|
37
40
|
|
|
38
41
|
##
|
|
39
42
|
# Thread-safe monitors for different contexts
|
|
@@ -178,8 +181,6 @@ module LLM
|
|
|
178
181
|
end
|
|
179
182
|
|
|
180
183
|
##
|
|
181
|
-
# @param [LLM::Provider, nil] llm
|
|
182
|
-
# The provider to use for MCP transports that need one
|
|
183
184
|
# @param [Hash, nil] stdio
|
|
184
185
|
# @option stdio [Array<String>] :argv
|
|
185
186
|
# The command to run for the MCP process
|
|
@@ -188,8 +189,27 @@ module LLM
|
|
|
188
189
|
# @option stdio [String, nil] :cwd
|
|
189
190
|
# The working directory for the MCP process
|
|
190
191
|
# @return [LLM::MCP]
|
|
191
|
-
def mcp(
|
|
192
|
-
LLM::MCP.new(
|
|
192
|
+
def mcp(**)
|
|
193
|
+
LLM::MCP.new(**)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
##
|
|
197
|
+
# Creates a new A2A client connected to a remote agent.
|
|
198
|
+
#
|
|
199
|
+
# @param [Hash, nil] http
|
|
200
|
+
# @option http [String] :url
|
|
201
|
+
# The base URL of the A2A agent (e.g., "https://agent.example.com")
|
|
202
|
+
# @option http [Hash<String, String>] :headers
|
|
203
|
+
# Extra HTTP headers (e.g., Authorization)
|
|
204
|
+
# @option http [Integer, nil] :timeout
|
|
205
|
+
# Request timeout in seconds
|
|
206
|
+
# @option http [LLM::Transport, Class, nil] :transport
|
|
207
|
+
# Optional transport override
|
|
208
|
+
# @param [Symbol] binding
|
|
209
|
+
# The protocol binding to use. One of `:rest` or `:jsonrpc`
|
|
210
|
+
# @return [LLM::A2A]
|
|
211
|
+
def a2a(http:, binding: :rest)
|
|
212
|
+
LLM::A2A.http(**http, binding:)
|
|
193
213
|
end
|
|
194
214
|
|
|
195
215
|
##
|
data/llm.gemspec
CHANGED
|
@@ -9,7 +9,22 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.email = ["azantar@proton.me", "0x1eef@hardenedbsd.org"]
|
|
10
10
|
|
|
11
11
|
spec.summary = "Ruby's most capable AI runtime"
|
|
12
|
-
spec.description =
|
|
12
|
+
spec.description = <<~DESC
|
|
13
|
+
llm.rb is Ruby's most capable AI runtime.
|
|
14
|
+
|
|
15
|
+
It runs on Ruby's standard library by default. loads optional pieces
|
|
16
|
+
only when needed, and offers a single runtime for providers, agents,
|
|
17
|
+
tools, skills, MCP, A2A (Agent2Agent), RAG (vector stores & embeddings),
|
|
18
|
+
streaming, files, and persisted state. As a bonus, llm.rb is also available
|
|
19
|
+
for mruby.
|
|
20
|
+
|
|
21
|
+
It supports OpenAI, OpenAI-compatible endpoints, Anthropic, Google
|
|
22
|
+
Gemini, DeepSeek, xAI, Z.ai, AWS Bedrock, Ollama, and llama.cpp. It
|
|
23
|
+
also includes built-in ActiveRecord and Sequel support, plus concurrent
|
|
24
|
+
tool execution through threads, tasks (via async gem), fibers, ractors,
|
|
25
|
+
and fork (via xchan.rb gem).
|
|
26
|
+
DESC
|
|
27
|
+
|
|
13
28
|
spec.license = "0BSD"
|
|
14
29
|
spec.required_ruby_version = ">= 3.3.0"
|
|
15
30
|
|
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
|
+
version: 11.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antar Azri
|
|
@@ -264,7 +264,20 @@ dependencies:
|
|
|
264
264
|
- - "~>"
|
|
265
265
|
- !ruby/object:Gem::Version
|
|
266
266
|
version: '1.5'
|
|
267
|
-
description:
|
|
267
|
+
description: |
|
|
268
|
+
llm.rb is Ruby's most capable AI runtime.
|
|
269
|
+
|
|
270
|
+
It runs on Ruby's standard library by default. loads optional pieces
|
|
271
|
+
only when needed, and offers a single runtime for providers, agents,
|
|
272
|
+
tools, skills, MCP, A2A (Agent2Agent), RAG (vector stores & embeddings),
|
|
273
|
+
streaming, files, and persisted state. As a bonus, llm.rb is also available
|
|
274
|
+
for mruby.
|
|
275
|
+
|
|
276
|
+
It supports OpenAI, OpenAI-compatible endpoints, Anthropic, Google
|
|
277
|
+
Gemini, DeepSeek, xAI, Z.ai, AWS Bedrock, Ollama, and llama.cpp. It
|
|
278
|
+
also includes built-in ActiveRecord and Sequel support, plus concurrent
|
|
279
|
+
tool execution through threads, tasks (via async gem), fibers, ractors,
|
|
280
|
+
and fork (via xchan.rb gem).
|
|
268
281
|
email:
|
|
269
282
|
- azantar@proton.me
|
|
270
283
|
- 0x1eef@hardenedbsd.org
|
|
@@ -283,11 +296,20 @@ files:
|
|
|
283
296
|
- data/xai.json
|
|
284
297
|
- data/zai.json
|
|
285
298
|
- lib/llm.rb
|
|
299
|
+
- lib/llm/a2a.rb
|
|
300
|
+
- lib/llm/a2a/card.rb
|
|
301
|
+
- lib/llm/a2a/card/capabilities.rb
|
|
302
|
+
- lib/llm/a2a/card/interface.rb
|
|
303
|
+
- lib/llm/a2a/card/provider.rb
|
|
304
|
+
- lib/llm/a2a/card/skill.rb
|
|
305
|
+
- lib/llm/a2a/error.rb
|
|
306
|
+
- lib/llm/a2a/notifications.rb
|
|
307
|
+
- lib/llm/a2a/tasks.rb
|
|
308
|
+
- lib/llm/a2a/transport/http.rb
|
|
286
309
|
- lib/llm/active_record.rb
|
|
287
310
|
- lib/llm/active_record/acts_as_agent.rb
|
|
288
311
|
- lib/llm/active_record/acts_as_llm.rb
|
|
289
312
|
- lib/llm/agent.rb
|
|
290
|
-
- lib/llm/bot.rb
|
|
291
313
|
- lib/llm/buffer.rb
|
|
292
314
|
- lib/llm/compactor.rb
|
|
293
315
|
- lib/llm/context.rb
|
|
@@ -305,6 +327,7 @@ files:
|
|
|
305
327
|
- lib/llm/function.rb
|
|
306
328
|
- lib/llm/function/array.rb
|
|
307
329
|
- lib/llm/function/call_group.rb
|
|
330
|
+
- lib/llm/function/call_task.rb
|
|
308
331
|
- lib/llm/function/fiber_group.rb
|
|
309
332
|
- lib/llm/function/fork.rb
|
|
310
333
|
- lib/llm/function/fork/job.rb
|
|
@@ -329,7 +352,6 @@ files:
|
|
|
329
352
|
- lib/llm/mcp/router.rb
|
|
330
353
|
- lib/llm/mcp/rpc.rb
|
|
331
354
|
- lib/llm/mcp/transport/http.rb
|
|
332
|
-
- lib/llm/mcp/transport/http/event_handler.rb
|
|
333
355
|
- lib/llm/mcp/transport/stdio.rb
|
|
334
356
|
- lib/llm/message.rb
|
|
335
357
|
- lib/llm/mime.rb
|
|
@@ -466,7 +488,9 @@ files:
|
|
|
466
488
|
- lib/llm/transport/response.rb
|
|
467
489
|
- lib/llm/transport/response/http.rb
|
|
468
490
|
- lib/llm/transport/stream_decoder.rb
|
|
491
|
+
- lib/llm/transport/utils.rb
|
|
469
492
|
- lib/llm/usage.rb
|
|
493
|
+
- lib/llm/utils.rb
|
|
470
494
|
- lib/llm/version.rb
|
|
471
495
|
- lib/sequel/plugins/agent.rb
|
|
472
496
|
- lib/sequel/plugins/llm.rb
|
|
@@ -493,7 +517,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
493
517
|
- !ruby/object:Gem::Version
|
|
494
518
|
version: '0'
|
|
495
519
|
requirements: []
|
|
496
|
-
rubygems_version: 4.0.
|
|
520
|
+
rubygems_version: 4.0.6
|
|
497
521
|
specification_version: 4
|
|
498
522
|
summary: Ruby's most capable AI runtime
|
|
499
523
|
test_files: []
|
data/lib/llm/bot.rb
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LLM::MCP::Transport
|
|
4
|
-
##
|
|
5
|
-
# The {LLM::MCP::Transport::HTTP::EventHandler LLM::MCP::Transport::HTTP::EventHandler}
|
|
6
|
-
# class adapts generic server-sent event callbacks into decoded JSON-RPC
|
|
7
|
-
# messages for {LLM::MCP::Transport::HTTP LLM::MCP::Transport::HTTP}.
|
|
8
|
-
# It accumulates event data until a blank line terminates the current
|
|
9
|
-
# event, then parses the payload as JSON and yields it to the callback
|
|
10
|
-
# given at initialization.
|
|
11
|
-
# @private
|
|
12
|
-
class HTTP::EventHandler
|
|
13
|
-
##
|
|
14
|
-
# @yieldparam [Hash] message
|
|
15
|
-
# A decoded JSON-RPC message
|
|
16
|
-
# @return [LLM::MCP::Transport::HTTP::EventHandler]
|
|
17
|
-
def initialize(&on_message)
|
|
18
|
-
@on_message = on_message
|
|
19
|
-
reset
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
##
|
|
23
|
-
# Receives the SSE event name.
|
|
24
|
-
# @param [LLM::EventStream::Event, String, nil] event
|
|
25
|
-
# @param [String, nil] chunk
|
|
26
|
-
# The event stream event
|
|
27
|
-
# @return [void]
|
|
28
|
-
def on_event(event, chunk = nil)
|
|
29
|
-
@event = chunk ? event : event.value
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
# Receives one line of SSE data.
|
|
34
|
-
# @param [LLM::EventStream::Event, String, nil] event
|
|
35
|
-
# @param [String, nil] chunk
|
|
36
|
-
# The event stream event
|
|
37
|
-
# @return [void]
|
|
38
|
-
def on_data(event, chunk = nil)
|
|
39
|
-
@data << (chunk ? event : event.value).to_s
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# The generic event stream parser dispatches one line at a time.
|
|
43
|
-
# A blank line terminates the current SSE event.
|
|
44
|
-
# @param [LLM::EventStream::Event, String] event
|
|
45
|
-
# The event stream event
|
|
46
|
-
# @return [void]
|
|
47
|
-
def on_chunk(event, chunk = nil)
|
|
48
|
-
flush if (chunk || event&.chunk || event) == "\n"
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
private
|
|
52
|
-
|
|
53
|
-
def flush
|
|
54
|
-
return reset if @data.empty? && @event.nil?
|
|
55
|
-
payload = @data.join("\n")
|
|
56
|
-
reset
|
|
57
|
-
return if payload.empty? || payload == "[DONE]"
|
|
58
|
-
@on_message.call(LLM.json.load(payload))
|
|
59
|
-
rescue *LLM.json.parser_error
|
|
60
|
-
reset
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def reset
|
|
64
|
-
@event = nil
|
|
65
|
-
@data = []
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|