llm.rb 15.0.0 → 15.0.1
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 +29 -0
- data/lib/llm/active_record/acts_as_agent.rb +1 -1
- data/lib/llm/active_record/acts_as_llm.rb +1 -1
- data/lib/llm/agent.rb +70 -48
- data/lib/llm/context.rb +7 -1
- data/lib/llm/sequel/agent.rb +1 -1
- data/lib/llm/sequel/plugin.rb +1 -1
- data/lib/llm/utils.rb +23 -1
- data/lib/llm/version.rb +1 -1
- data/llm.gemspec +9 -3
- metadata +6 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ce996689c82e7a0d62a7f09ab2545d10b36462fc75cc2feeb57ce26f6523585
|
|
4
|
+
data.tar.gz: 74cf140b0fd11b077aea57bde027f0b00cf67f4e099ad35778bc5042b958469b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4274138e7054d9db54e121dcad674f307b0e1bdbfc568ac16bb3b13181e873a77a57d19f4d2eef2479216555ba0ed9213fa7372cf051d4fa73f6fe73dae594cd
|
|
7
|
+
data.tar.gz: 12219c398f482c7f949bc9964038a2597e74a592b78023b101e96a337605c2e2fb8963f5526fbd4ca8f1ffd8b14b843e1a10334369d2f62a1e393eb409f4821d
|
data/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,35 @@
|
|
|
15
15
|
|
|
16
16
|
## What's next
|
|
17
17
|
|
|
18
|
+
## v15.0.1
|
|
19
|
+
|
|
20
|
+
Changes since `v15.0.0`.
|
|
21
|
+
|
|
22
|
+
This release fixes agent `set` handling of single `Symbol`/`Proc`
|
|
23
|
+
values and resolves ORM options as `Symbol`s through the bound record
|
|
24
|
+
instead of the `LLM::Agent` instance.
|
|
25
|
+
|
|
26
|
+
### Agent
|
|
27
|
+
|
|
28
|
+
* **agent: fix `set (skills|tools): Symbol|Proc`** <br>
|
|
29
|
+
The `skills`, `tools`, `confirm`, and `schema` class accessors now
|
|
30
|
+
consistently resolve a single `Symbol` or `Proc` lazily at agent
|
|
31
|
+
initialization, so `LLM::Agent.set(skills: proc { [...] })` and
|
|
32
|
+
`LLM::Agent.set(tools: :tools)` no longer raise. The `set` family
|
|
33
|
+
shares one `single_callable?` helper rather than each accessor
|
|
34
|
+
duplicating its own logic.
|
|
35
|
+
|
|
36
|
+
### Fix
|
|
37
|
+
|
|
38
|
+
* **orm: resolve a `Symbol` through the bound record** <br>
|
|
39
|
+
When an ORM model using `acts_as_agent` (ActiveRecord), `plugin :agent`
|
|
40
|
+
(Sequel), or `acts_as_llm` / `plugin :llm` configures an option as a
|
|
41
|
+
`Symbol`, that symbol is now resolved on the model instance (or its
|
|
42
|
+
bound record) instead of the `LLM::Agent` instance. The contexts and
|
|
43
|
+
agents built by the wrappers are now bound to the record, so a model like
|
|
44
|
+
`agent.set :tools` with a `tools` method on the record works as
|
|
45
|
+
expected.
|
|
46
|
+
|
|
18
47
|
## v15.0.0
|
|
19
48
|
|
|
20
49
|
Changes since `v14.0.0`.
|
|
@@ -126,7 +126,7 @@ module LLM::ActiveRecord
|
|
|
126
126
|
@ctx ||= begin
|
|
127
127
|
options = self.class.llm_plugin_options
|
|
128
128
|
params = Utils.resolve_options(self, options[:context], EMPTY_HASH).dup
|
|
129
|
-
ctx = self.class.agent.new(llm, params.compact)
|
|
129
|
+
ctx = self.class.agent.new(llm, params.compact.merge(record: self))
|
|
130
130
|
columns = Utils.columns(options)
|
|
131
131
|
data = self[columns[:data_column]]
|
|
132
132
|
if data.nil? || data == ""
|
|
@@ -243,7 +243,7 @@ module LLM::ActiveRecord
|
|
|
243
243
|
options = self.class.llm_plugin_options
|
|
244
244
|
columns = Utils.columns(options)
|
|
245
245
|
params = Utils.resolve_options(self, options[:context], EMPTY_HASH).dup
|
|
246
|
-
ctx = LLM::Context.new(llm, params.compact)
|
|
246
|
+
ctx = LLM::Context.new(llm, params.compact.merge(record: self))
|
|
247
247
|
data = self[columns[:data_column]]
|
|
248
248
|
if data.nil? || data == ""
|
|
249
249
|
ctx
|
data/lib/llm/agent.rb
CHANGED
|
@@ -57,14 +57,16 @@ module LLM
|
|
|
57
57
|
##
|
|
58
58
|
# Ugh :)
|
|
59
59
|
# @api private
|
|
60
|
-
FIELDS = %i[
|
|
60
|
+
FIELDS = %i[record
|
|
61
|
+
name description
|
|
61
62
|
path tool_budget
|
|
62
63
|
retry_budget model
|
|
63
64
|
skills schema
|
|
64
65
|
tracer stream
|
|
65
66
|
tools concurrency
|
|
66
67
|
instructions confirm]
|
|
67
|
-
IVARS = %i[
|
|
68
|
+
IVARS = %i[record
|
|
69
|
+
name description
|
|
68
70
|
path tool_budget
|
|
69
71
|
tracer concurrency
|
|
70
72
|
instructions confirm]
|
|
@@ -169,10 +171,21 @@ module LLM
|
|
|
169
171
|
# @return [String, nil]
|
|
170
172
|
# Returns the current model when no argument is provided
|
|
171
173
|
def self.model(model = nil, &block)
|
|
172
|
-
return @model if model.nil?
|
|
174
|
+
return @model if model.nil? and !block
|
|
173
175
|
@model = block || model
|
|
174
176
|
end
|
|
175
177
|
|
|
178
|
+
##
|
|
179
|
+
# Set or get the default schema
|
|
180
|
+
# @param [#to_json, nil] schema
|
|
181
|
+
# The schema
|
|
182
|
+
# @return [#to_json, nil]
|
|
183
|
+
# Returns the current schema when no argument is provided
|
|
184
|
+
def self.schema(schema = nil, &block)
|
|
185
|
+
return @schema if schema.nil? and !block
|
|
186
|
+
@schema = block || schema
|
|
187
|
+
end
|
|
188
|
+
|
|
176
189
|
##
|
|
177
190
|
# Set or get the default tools
|
|
178
191
|
# @param [Array<LLM::Function>, nil] tools
|
|
@@ -180,11 +193,13 @@ module LLM
|
|
|
180
193
|
# @return [Array<LLM::Function>]
|
|
181
194
|
# Returns the current tools when no argument is provided
|
|
182
195
|
def self.tools(*tools, &block)
|
|
183
|
-
return @tools || [] if tools.empty?
|
|
184
|
-
if
|
|
196
|
+
return @tools || [] if tools.empty? and !block
|
|
197
|
+
if block
|
|
198
|
+
@tools = block
|
|
199
|
+
elsif single_callable?(tools)
|
|
185
200
|
@tools = tools.first
|
|
186
201
|
else
|
|
187
|
-
@tools =
|
|
202
|
+
@tools = tools.flatten
|
|
188
203
|
end
|
|
189
204
|
end
|
|
190
205
|
|
|
@@ -195,23 +210,46 @@ module LLM
|
|
|
195
210
|
# @return [Array<String>, nil]
|
|
196
211
|
# Returns the current skills when no argument is provided
|
|
197
212
|
def self.skills(*skills, &block)
|
|
198
|
-
return @skills if skills.empty?
|
|
199
|
-
if
|
|
213
|
+
return @skills if skills.empty? and !block
|
|
214
|
+
if block
|
|
215
|
+
@skills = block
|
|
216
|
+
elsif single_callable?(skills)
|
|
200
217
|
@skills = skills.first
|
|
201
218
|
else
|
|
202
|
-
@skills =
|
|
219
|
+
@skills = skills.flatten
|
|
203
220
|
end
|
|
204
221
|
end
|
|
205
222
|
|
|
206
223
|
##
|
|
207
|
-
# Set or get the
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
224
|
+
# Set or get the tool names that require confirmation before they can run.
|
|
225
|
+
#
|
|
226
|
+
# When a single Symbol is given, it is stored as-is and resolved at
|
|
227
|
+
# initialization time by calling the method with that name on the agent
|
|
228
|
+
# instance. This allows dynamic tool confirmation lists.
|
|
229
|
+
#
|
|
230
|
+
# @example
|
|
231
|
+
# class MyAgent < LLM::Agent
|
|
232
|
+
# confirm :tools_that_need_confirmation
|
|
233
|
+
#
|
|
234
|
+
# def tools_that_need_confirmation
|
|
235
|
+
# some_condition ? %w[delete destroy] : %w[delete]
|
|
236
|
+
# end
|
|
237
|
+
# end
|
|
238
|
+
#
|
|
239
|
+
# @param [String, Symbol, Array<String, Symbol>, Proc] tool_names
|
|
240
|
+
# One or more tool names.
|
|
241
|
+
# @param [Proc] block
|
|
242
|
+
# An optional, lazy-evaluated Proc
|
|
243
|
+
# @return [Array<String>, Proc, Symbol, nil]
|
|
244
|
+
def self.confirm(*tool_names, &block)
|
|
245
|
+
return @confirm if tool_names.empty? and !block
|
|
246
|
+
if block
|
|
247
|
+
@confirm = block
|
|
248
|
+
elsif single_callable?(tool_names)
|
|
249
|
+
@confirm = tool_names.first
|
|
250
|
+
else
|
|
251
|
+
@confirm = tool_names.flatten.map(&:to_s)
|
|
252
|
+
end
|
|
215
253
|
end
|
|
216
254
|
|
|
217
255
|
##
|
|
@@ -285,36 +323,6 @@ module LLM
|
|
|
285
323
|
@stream = block || stream
|
|
286
324
|
end
|
|
287
325
|
|
|
288
|
-
##
|
|
289
|
-
# Set or get the tool names that require confirmation before they can run.
|
|
290
|
-
#
|
|
291
|
-
# When a single Symbol is given, it is stored as-is and resolved at
|
|
292
|
-
# initialization time by calling the method with that name on the agent
|
|
293
|
-
# instance. This allows dynamic tool confirmation lists.
|
|
294
|
-
#
|
|
295
|
-
# @example
|
|
296
|
-
# class MyAgent < LLM::Agent
|
|
297
|
-
# confirm :tools_that_need_confirmation
|
|
298
|
-
#
|
|
299
|
-
# def tools_that_need_confirmation
|
|
300
|
-
# some_condition ? %w[delete destroy] : %w[delete]
|
|
301
|
-
# end
|
|
302
|
-
# end
|
|
303
|
-
#
|
|
304
|
-
# @param [String, Symbol, Array<String, Symbol>, Proc] tool_names
|
|
305
|
-
# One or more tool names.
|
|
306
|
-
# @param [Proc] block
|
|
307
|
-
# An optional, lazy-evaluated Proc
|
|
308
|
-
# @return [Array<String>, Proc, Symbol, nil]
|
|
309
|
-
def self.confirm(*tool_names, &block)
|
|
310
|
-
return @confirm if tool_names.empty? && !block
|
|
311
|
-
if tool_names.size == 1 && tool_names.grep(Symbol).any?
|
|
312
|
-
@confirm = tool_names.first
|
|
313
|
-
else
|
|
314
|
-
@confirm = block || tool_names.flatten.map(&:to_s)
|
|
315
|
-
end
|
|
316
|
-
end
|
|
317
|
-
|
|
318
326
|
##
|
|
319
327
|
# Set the file path where an agent's memory
|
|
320
328
|
# can be restored from, and written to.
|
|
@@ -370,6 +378,13 @@ module LLM
|
|
|
370
378
|
end
|
|
371
379
|
end
|
|
372
380
|
|
|
381
|
+
##
|
|
382
|
+
# @api private
|
|
383
|
+
def self.single_callable?(callable)
|
|
384
|
+
callable.size == 1 and (Proc === callable[0] or Symbol === callable[0])
|
|
385
|
+
end
|
|
386
|
+
private_class_method :single_callable?
|
|
387
|
+
|
|
373
388
|
##
|
|
374
389
|
# @param [LLM::Provider] llm
|
|
375
390
|
# A provider
|
|
@@ -389,7 +404,7 @@ module LLM
|
|
|
389
404
|
@llm = llm
|
|
390
405
|
fields, fields_ivar = FIELDS, IVARS
|
|
391
406
|
fields.each do |field|
|
|
392
|
-
resolvable = params.key?(field) ? params.delete(field) : self.class.public_send(field)
|
|
407
|
+
resolvable = params.key?(field) ? params.delete(field) : (self.class.respond_to?(field) ? self.class.public_send(field) : nil)
|
|
393
408
|
resolve_symbol = !%i[concurrency].include?(field)
|
|
394
409
|
resolved = resolvable != nil ? resolve_option(self, resolvable, resolve_symbol:) : resolvable
|
|
395
410
|
resolved = [*resolved].map(&:to_s) if field == :confirm && resolved
|
|
@@ -420,6 +435,13 @@ module LLM
|
|
|
420
435
|
@path
|
|
421
436
|
end
|
|
422
437
|
|
|
438
|
+
##
|
|
439
|
+
# Returns the ORM record this agent is bound to, or nil.
|
|
440
|
+
# @return [Object, nil]
|
|
441
|
+
def record
|
|
442
|
+
@record
|
|
443
|
+
end
|
|
444
|
+
|
|
423
445
|
##
|
|
424
446
|
# Returns the agent's description
|
|
425
447
|
# @return [String, nil]
|
data/lib/llm/context.rb
CHANGED
|
@@ -46,7 +46,7 @@ module LLM
|
|
|
46
46
|
# @api private
|
|
47
47
|
# @return [Array<Symbol>]
|
|
48
48
|
def self.params
|
|
49
|
-
%w[guard retry_budget concurrency transformer compactor]
|
|
49
|
+
%w[guard retry_budget concurrency transformer compactor record]
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
##
|
|
@@ -64,6 +64,11 @@ module LLM
|
|
|
64
64
|
# @return [Symbol]
|
|
65
65
|
attr_reader :mode
|
|
66
66
|
|
|
67
|
+
##
|
|
68
|
+
# Returns the ORM record this context is bound to, or nil.
|
|
69
|
+
# @return [Object, nil]
|
|
70
|
+
attr_reader :record
|
|
71
|
+
|
|
67
72
|
##
|
|
68
73
|
# @param [LLM::Provider] llm
|
|
69
74
|
# A provider
|
|
@@ -95,6 +100,7 @@ module LLM
|
|
|
95
100
|
def initialize(llm, params = {})
|
|
96
101
|
params = {}.merge!(params)
|
|
97
102
|
@llm = llm
|
|
103
|
+
@record = params.delete(:record)
|
|
98
104
|
@mode = params.delete(:mode) || (llm.name == :openai ? :responses : :completions)
|
|
99
105
|
tools = [*params.delete(:tools), *load_skills(params.delete(:skills))]
|
|
100
106
|
@params = {model: llm.default_model, schema: nil}.compact.merge!(params)
|
data/lib/llm/sequel/agent.rb
CHANGED
|
@@ -88,7 +88,7 @@ module LLM::Sequel
|
|
|
88
88
|
options = self.class.llm_plugin_options
|
|
89
89
|
columns = Agent::Utils.columns(options)
|
|
90
90
|
params = Agent::Utils.resolve_options(self, options[:context], Agent::EMPTY_HASH).dup
|
|
91
|
-
ctx = self.class.agent.new(llm, params.compact)
|
|
91
|
+
ctx = self.class.agent.new(llm, params.compact.merge(record: self))
|
|
92
92
|
data = self[columns[:data_column]]
|
|
93
93
|
if data.nil? || data == ""
|
|
94
94
|
ctx
|
data/lib/llm/sequel/plugin.rb
CHANGED
|
@@ -343,7 +343,7 @@ module LLM::Sequel
|
|
|
343
343
|
options = self.class.llm_plugin_options
|
|
344
344
|
columns = Utils.columns(options)
|
|
345
345
|
params = Utils.resolve_options(self, options[:context], Plugin::EMPTY_HASH).dup
|
|
346
|
-
ctx = LLM::Context.new(llm, params.compact)
|
|
346
|
+
ctx = LLM::Context.new(llm, params.compact.merge(record: self))
|
|
347
347
|
data = self[columns[:data_column]]
|
|
348
348
|
if data.nil? || data == ""
|
|
349
349
|
ctx
|
data/lib/llm/utils.rb
CHANGED
|
@@ -20,12 +20,34 @@ module LLM
|
|
|
20
20
|
def resolve_option(obj, option, resolve_symbol: true)
|
|
21
21
|
case option
|
|
22
22
|
when Proc then obj.instance_exec(&option)
|
|
23
|
-
when Symbol
|
|
23
|
+
when Symbol
|
|
24
|
+
if resolve_symbol
|
|
25
|
+
if obj.respond_to?(option, true) and record?(obj)
|
|
26
|
+
obj.send(option)
|
|
27
|
+
elsif obj.respond_to?(:record) and obj.record.respond_to?(option, true)
|
|
28
|
+
obj.record.send(option)
|
|
29
|
+
elsif obj.respond_to?(option, true)
|
|
30
|
+
obj.send(option)
|
|
31
|
+
else
|
|
32
|
+
raise ArgumentError, "unable to resolve #{option}"
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
option
|
|
36
|
+
end
|
|
24
37
|
when Hash then option.dup
|
|
25
38
|
else option
|
|
26
39
|
end
|
|
27
40
|
end
|
|
28
41
|
|
|
42
|
+
##
|
|
43
|
+
# Returns true when `obj` is an ActiveRecord or Sequel model.
|
|
44
|
+
# @param [Object] obj
|
|
45
|
+
# @api private
|
|
46
|
+
def record?(obj)
|
|
47
|
+
(defined?(::ActiveRecord::Base) and ::ActiveRecord::Base === obj) or
|
|
48
|
+
(defined?(::Sequel::Model) and ::Sequel::Model === obj)
|
|
49
|
+
end
|
|
50
|
+
|
|
29
51
|
##
|
|
30
52
|
# Normalizes an HTTP API base path.
|
|
31
53
|
#
|
data/lib/llm/version.rb
CHANGED
data/llm.gemspec
CHANGED
|
@@ -21,7 +21,7 @@ DESCRIPTION
|
|
|
21
21
|
spec.license = "MIT"
|
|
22
22
|
spec.required_ruby_version = ">= 3.3.0"
|
|
23
23
|
|
|
24
|
-
spec.homepage = "https://r.uby.dev
|
|
24
|
+
spec.homepage = "https://r.uby.dev"
|
|
25
25
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
26
26
|
spec.metadata["source_code_uri"] = "https://github.com/r-uby-dev/llm"
|
|
27
27
|
spec.metadata["documentation_uri"] = spec.homepage
|
|
@@ -38,9 +38,15 @@ DESCRIPTION
|
|
|
38
38
|
spec.executables = ["llm.rb"]
|
|
39
39
|
spec.require_paths = ["lib"]
|
|
40
40
|
spec.post_install_message = "\n" \
|
|
41
|
-
"
|
|
41
|
+
"Got a question about llm.rb? " \
|
|
42
42
|
"\n" \
|
|
43
|
-
"
|
|
43
|
+
"Ask our chatbot." \
|
|
44
|
+
"\n" \
|
|
45
|
+
"It is connected to the official GitHub repository." \
|
|
46
|
+
"\n" \
|
|
47
|
+
"100% free to use." \
|
|
48
|
+
"\n" \
|
|
49
|
+
"https://r.uby.dev" \
|
|
44
50
|
"\n\n"
|
|
45
51
|
|
|
46
52
|
spec.add_development_dependency "webmock", "~> 3.24.0"
|
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: 15.0.
|
|
4
|
+
version: 15.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Gleeson
|
|
@@ -644,19 +644,16 @@ files:
|
|
|
644
644
|
- lib/sequel/plugins/agent.rb
|
|
645
645
|
- lib/sequel/plugins/llm.rb
|
|
646
646
|
- llm.gemspec
|
|
647
|
-
homepage: https://r.uby.dev
|
|
647
|
+
homepage: https://r.uby.dev
|
|
648
648
|
licenses:
|
|
649
649
|
- MIT
|
|
650
650
|
metadata:
|
|
651
|
-
homepage_uri: https://r.uby.dev
|
|
651
|
+
homepage_uri: https://r.uby.dev
|
|
652
652
|
source_code_uri: https://github.com/r-uby-dev/llm
|
|
653
|
-
documentation_uri: https://r.uby.dev
|
|
653
|
+
documentation_uri: https://r.uby.dev
|
|
654
654
|
changelog_uri: https://github.com/r-uby-dev/llm/blob/main/CHANGELOG.md
|
|
655
|
-
post_install_message:
|
|
656
|
-
|
|
657
|
-
Learn more about llm.rb on GitHub:
|
|
658
|
-
https://github.com/r-uby-dev/llm#readme
|
|
659
|
-
|
|
655
|
+
post_install_message: "\nGot a question about llm.rb? \nAsk our chatbot.\nIt is connected
|
|
656
|
+
to the official GitHub repository.\n100% free to use.\nhttps://r.uby.dev\n\n"
|
|
660
657
|
rdoc_options: []
|
|
661
658
|
require_paths:
|
|
662
659
|
- lib
|
|
@@ -675,4 +672,3 @@ rubygems_version: 4.0.16
|
|
|
675
672
|
specification_version: 4
|
|
676
673
|
summary: Ruby's capable AI runtime
|
|
677
674
|
test_files: []
|
|
678
|
-
...
|