llm.rb 11.0.0 → 11.1.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 +42 -0
- data/README.md +32 -15
- data/lib/llm/context.rb +21 -0
- data/lib/llm/function.rb +12 -4
- data/lib/llm/object/builder.rb +1 -0
- data/lib/llm/object.rb +9 -0
- data/lib/llm/schema.rb +23 -5
- data/lib/llm/skill.rb +44 -14
- data/lib/llm/tracer/telemetry.rb +3 -1
- data/lib/llm/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5bb91948d8cfa006f7512dd0a4fa62f90b42360e3f11a57074870470fdc70d3f
|
|
4
|
+
data.tar.gz: 64b49f633318bc0439252cebca4c3886db4c7676f3cb9a78f4945eefe58b4356
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c56b48185604b22c44f7b4697da56a5fda8359a69e110392abf2510b47a4dc9aedbe5c6a9e64e733fafb5672c34d4a0833448fab5ca9de52c453c8a906080174
|
|
7
|
+
data.tar.gz: a2a9241da0e8749569111573451c99c92ed3569fa7cee0c9178b8aa884a72b27a24f18e19566cef8a16c2e460420a392b83d441708da67a571a9e2648d4d81e2
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v11.1.0
|
|
6
|
+
|
|
7
|
+
Changes since `v11.0.0`.
|
|
8
|
+
|
|
9
|
+
This release adds the `inherit` directive for skill sub-agents so they can
|
|
10
|
+
inherit access to the local, MCP, and A2A tools available to their parent
|
|
11
|
+
agent. It introduces class-level `required %i[...]` declarations to
|
|
12
|
+
`LLM::Schema` and wraps `LLM::Function#arguments` in `LLM::Object` for
|
|
13
|
+
method-style argument access. The OpenTelemetry tracer now samples all spans
|
|
14
|
+
regardless of environment, and the tool-call loop repair step prevents stale
|
|
15
|
+
history from being sent on follow-up requests.
|
|
16
|
+
|
|
17
|
+
### Add
|
|
18
|
+
|
|
19
|
+
* **Add support for the `inherit` directive in skills** <br>
|
|
20
|
+
Add support for the `inherit` directive so a skill sub-agent can
|
|
21
|
+
inherit access to the local, MCP, and A2A tools available to its
|
|
22
|
+
parent agent.
|
|
23
|
+
|
|
24
|
+
* **Add class-level `required %i[...]` support to `LLM::Schema`** <br>
|
|
25
|
+
Add class-level `required %i[...]` declarations to `LLM::Schema`, so
|
|
26
|
+
schema classes can mark existing properties as required the same way
|
|
27
|
+
`LLM::Tool` params already can.
|
|
28
|
+
|
|
29
|
+
* **Wrap function arguments in `LLM::Object`** <br>
|
|
30
|
+
Wrap `LLM::Function#arguments` in `LLM::Object`, so function
|
|
31
|
+
implementations can read arguments with method-style access while
|
|
32
|
+
still invoking runners with keyword arguments.
|
|
33
|
+
|
|
34
|
+
### Fix
|
|
35
|
+
|
|
36
|
+
* **Ensure all traces are sampled regardless of environment** <br>
|
|
37
|
+
Explicitly pass `Samplers::ALWAYS_ON` when creating the OpenTelemetry
|
|
38
|
+
`TracerProvider` so the in-memory exporter always captures every span,
|
|
39
|
+
regardless of the `OTEL_TRACES_SAMPLER` environment variable.
|
|
40
|
+
|
|
41
|
+
* **Always close the tool call loop before sending follow-up requests** <br>
|
|
42
|
+
Add a repair step in `Context#talk` that closes assistant tool-call
|
|
43
|
+
messages without matching tool responses before the next provider
|
|
44
|
+
request is sent. This prevents stale tool-call history from being sent
|
|
45
|
+
on follow-up requests, which some providers reject as invalid.
|
|
46
|
+
|
|
5
47
|
## v11.0.0
|
|
6
48
|
|
|
7
49
|
Changes since `v10.0.0`.
|
data/README.md
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
<p align="center">
|
|
7
|
-
<a href="https://
|
|
8
|
-
<img src="https://img.shields.io/badge/docs-
|
|
7
|
+
<a href="https://llmrb.github.io/llm.rb">
|
|
8
|
+
<img src="https://img.shields.io/badge/docs-llmrb.github.io-blue.svg" alt="Official llm.rb website">
|
|
9
9
|
</a>
|
|
10
10
|
<a href="https://opensource.org/license/0bsd">
|
|
11
11
|
<img src="https://img.shields.io/badge/License-0BSD-orange.svg?" alt="License">
|
|
12
12
|
</a>
|
|
13
13
|
<a href="https://github.com/llmrb/llm.rb/tags">
|
|
14
|
-
<img src="https://img.shields.io/badge/version-11.
|
|
14
|
+
<img src="https://img.shields.io/badge/version-11.1.0-green.svg?" alt="Version">
|
|
15
15
|
</a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
@@ -22,8 +22,7 @@ llm.rb is Ruby's most capable AI runtime.
|
|
|
22
22
|
It runs on Ruby's standard library by default. loads optional pieces
|
|
23
23
|
only when needed, and offers a single runtime for providers, agents,
|
|
24
24
|
tools, skills, MCP, A2A (Agent2Agent), RAG (vector stores & embeddings),
|
|
25
|
-
streaming, files, and persisted state.
|
|
26
|
-
[available for mruby](https://github.com/llmrb/mruby-llm).
|
|
25
|
+
streaming, files, and persisted state.
|
|
27
26
|
|
|
28
27
|
It supports OpenAI, OpenAI-compatible endpoints, Anthropic, Google
|
|
29
28
|
Gemini, DeepSeek, xAI, Z.ai, AWS Bedrock, Ollama, and llama.cpp. It
|
|
@@ -31,6 +30,11 @@ also includes built-in ActiveRecord and Sequel support, plus concurrent
|
|
|
31
30
|
tool execution through threads, tasks (via async gem), fibers, ractors,
|
|
32
31
|
and fork (via xchan.rb gem).
|
|
33
32
|
|
|
33
|
+
As a bonus, llm.rb is also available to embedded systems [via mruby](https://github.com/llmrb/mruby-llm#readme),
|
|
34
|
+
to the browser and edge devices [via WebAssembly](https://github.com/llmrb/wasm-llm#readme),
|
|
35
|
+
and has first-class [Rails support](https://github.com/llmrb/rails-llm#readme)
|
|
36
|
+
via a separate gem.
|
|
37
|
+
|
|
34
38
|
## Quick start
|
|
35
39
|
|
|
36
40
|
#### LLM::Context
|
|
@@ -90,7 +94,7 @@ class Agent < LLM::Agent
|
|
|
90
94
|
confirm "delete-file"
|
|
91
95
|
|
|
92
96
|
def on_tool_confirmation(fn, strategy)
|
|
93
|
-
path = fn.arguments
|
|
97
|
+
path = fn.arguments.path
|
|
94
98
|
if path.start_with?("/tmp/")
|
|
95
99
|
fn.spawn(strategy).wait
|
|
96
100
|
else
|
|
@@ -260,6 +264,19 @@ llm = LLM.openai(key: ENV["KEY"])
|
|
|
260
264
|
ReleaseAgent.new(llm, stream: $stdout).talk("Prepare the next release.")
|
|
261
265
|
```
|
|
262
266
|
|
|
267
|
+
A skill can also have its sub-agent inherit the parents tools through the
|
|
268
|
+
`inherit` directive. The `inherit` directive has coverage for the "classic"
|
|
269
|
+
tools (a subclass of [LLM::Tool](https://0x1eef.github.io/x/llm.rb/LLM/Tool.html)),
|
|
270
|
+
MCP tools, and A2A tools that a parent context or agent has access to:
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
---
|
|
274
|
+
name: release
|
|
275
|
+
description: Prepare a release
|
|
276
|
+
tools: inherit
|
|
277
|
+
---
|
|
278
|
+
```
|
|
279
|
+
|
|
263
280
|
#### LLM::Stream
|
|
264
281
|
|
|
265
282
|
The
|
|
@@ -389,7 +406,7 @@ gem install llm.rb
|
|
|
389
406
|
|
|
390
407
|
This example uses [`LLM::Context`](https://0x1eef.github.io/x/llm.rb/LLM/Context.html)
|
|
391
408
|
directly for an interactive REPL. <br> See the
|
|
392
|
-
[deepdive (web)](https://
|
|
409
|
+
[deepdive (web)](https://llmrb.github.io/llm.rb/) or
|
|
393
410
|
[deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
394
411
|
|
|
395
412
|
```ruby
|
|
@@ -442,7 +459,7 @@ different model from the main context. `token_threshold:` accepts either a
|
|
|
442
459
|
fixed token count or a percentage string like `"90%"`, which resolves
|
|
443
460
|
against the active model context window and triggers compaction once total
|
|
444
461
|
token usage goes over that percentage. See the
|
|
445
|
-
[deepdive (web)](https://
|
|
462
|
+
[deepdive (web)](https://llmrb.github.io/llm.rb/) or
|
|
446
463
|
[deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
447
464
|
|
|
448
465
|
```ruby
|
|
@@ -475,7 +492,7 @@ ctx = LLM::Context.new(
|
|
|
475
492
|
This example uses [`LLM::Stream`](https://0x1eef.github.io/x/llm.rb/LLM/Stream.html)
|
|
476
493
|
with the OpenAI Responses API so reasoning output is streamed separately from
|
|
477
494
|
visible assistant output. See the
|
|
478
|
-
[deepdive (web)](https://
|
|
495
|
+
[deepdive (web)](https://llmrb.github.io/llm.rb/) or
|
|
479
496
|
[deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
480
497
|
|
|
481
498
|
To use the Responses API (OpenAI-specific), initialize a
|
|
@@ -510,7 +527,7 @@ ctx.talk("Solve 17 * 19 and show your work.")
|
|
|
510
527
|
|
|
511
528
|
Need to cancel a stream? llm.rb has you covered through
|
|
512
529
|
[`LLM::Context#interrupt!`](https://0x1eef.github.io/x/llm.rb/LLM/Context.html#interrupt-21-instance_method).
|
|
513
|
-
<br> See the [deepdive (web)](https://
|
|
530
|
+
<br> See the [deepdive (web)](https://llmrb.github.io/llm.rb/)
|
|
514
531
|
or [deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
515
532
|
|
|
516
533
|
```ruby
|
|
@@ -538,7 +555,7 @@ The `plugin :llm` integration wraps
|
|
|
538
555
|
wrappers, its built-in persistence contract is the serialized `data` column,
|
|
539
556
|
while `provider:` resolves a real `LLM::Provider` instance and `context:`
|
|
540
557
|
injects defaults such as `model:`. <br> See the
|
|
541
|
-
[deepdive (web)](https://
|
|
558
|
+
[deepdive (web)](https://llmrb.github.io/llm.rb/) or
|
|
542
559
|
[deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
543
560
|
|
|
544
561
|
```ruby
|
|
@@ -574,7 +591,7 @@ one serialized `data` column. If your app has provider, model, or usage
|
|
|
574
591
|
columns, provide them to llm.rb through `provider:` and `context:` instead of
|
|
575
592
|
relying on reserved wrapper columns.
|
|
576
593
|
|
|
577
|
-
See the [deepdive (web)](https://
|
|
594
|
+
See the [deepdive (web)](https://llmrb.github.io/llm.rb/)
|
|
578
595
|
or [deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
579
596
|
|
|
580
597
|
```ruby
|
|
@@ -631,7 +648,7 @@ manages tool execution for you. Like `acts_as_llm`, its built-in persistence
|
|
|
631
648
|
contract is one serialized `data` column. If your app has provider or model
|
|
632
649
|
columns, provide them to llm.rb through your hooks and agent DSL.
|
|
633
650
|
|
|
634
|
-
See the [deepdive (web)](https://
|
|
651
|
+
See the [deepdive (web)](https://llmrb.github.io/llm.rb/)
|
|
635
652
|
or [deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
636
653
|
|
|
637
654
|
```ruby
|
|
@@ -689,7 +706,7 @@ This example uses [`LLM::MCP`](https://0x1eef.github.io/x/llm.rb/LLM/MCP.html)
|
|
|
689
706
|
over HTTP so remote GitHub MCP tools run through the same
|
|
690
707
|
`LLM::Context` tool path as local tools. It expects a GitHub token in
|
|
691
708
|
`ENV["GITHUB_PAT"]`. See the
|
|
692
|
-
[deepdive (web)](https://
|
|
709
|
+
[deepdive (web)](https://llmrb.github.io/llm.rb/) or
|
|
693
710
|
[deepdive (markdown)](resources/deepdive.md) for more examples.
|
|
694
711
|
|
|
695
712
|
```ruby
|
|
@@ -710,7 +727,7 @@ ctx.talk(ctx.wait(:call)) while ctx.functions?
|
|
|
710
727
|
|
|
711
728
|
## Resources
|
|
712
729
|
|
|
713
|
-
- [deepdive (web)](https://
|
|
730
|
+
- [deepdive (web)](https://llmrb.github.io/llm.rb/) and
|
|
714
731
|
[deepdive (markdown)](resources/deepdive.md) are the examples guide.
|
|
715
732
|
- [relay](https://github.com/llmrb/relay) shows a real application built on
|
|
716
733
|
top of llm.rb.
|
data/lib/llm/context.rb
CHANGED
|
@@ -193,6 +193,7 @@ module LLM
|
|
|
193
193
|
def talk(prompt, params = {})
|
|
194
194
|
@owner = @llm.request_owner
|
|
195
195
|
compactor.compact!(prompt) if compactor.compact?(prompt)
|
|
196
|
+
repair!(@messages, prompt)
|
|
196
197
|
prompt, params, res = mode == :responses ? respond(prompt, params) : complete(prompt, params)
|
|
197
198
|
self.compacted = false
|
|
198
199
|
role = params[:role] || @llm.user_role
|
|
@@ -566,5 +567,25 @@ module LLM
|
|
|
566
567
|
message: warning
|
|
567
568
|
})
|
|
568
569
|
end
|
|
570
|
+
|
|
571
|
+
##
|
|
572
|
+
# Closes assistant tool-call messages that do not have matching tool
|
|
573
|
+
# responses. This can happen when a turn is interrupted while a tool
|
|
574
|
+
# call is streaming or waiting for user confirmation.
|
|
575
|
+
# @param [Array<LLM::Message>] messages
|
|
576
|
+
# @param [Object] prompt
|
|
577
|
+
# @return [void]
|
|
578
|
+
def repair!(messages, prompt)
|
|
579
|
+
message = messages.last
|
|
580
|
+
return unless message&.tool_call?
|
|
581
|
+
returns = self.returns + [*prompt].grep(LLM::Function::Return)
|
|
582
|
+
cancelled = []
|
|
583
|
+
[*message.extra.tool_calls].each do |tool|
|
|
584
|
+
next if returns.any? { _1.id == tool[:id] }
|
|
585
|
+
attrs = {cancelled: true, reason: "function call cancelled"}
|
|
586
|
+
cancelled << LLM::Function::Return.new(tool.id, tool.name, attrs)
|
|
587
|
+
end
|
|
588
|
+
messages << LLM::Message.new(@llm.tool_role, cancelled) unless cancelled.empty?
|
|
589
|
+
end
|
|
569
590
|
end
|
|
570
591
|
end
|
data/lib/llm/function.rb
CHANGED
|
@@ -109,8 +109,16 @@ class LLM::Function
|
|
|
109
109
|
|
|
110
110
|
##
|
|
111
111
|
# Returns function arguments
|
|
112
|
-
# @return [Array, nil]
|
|
113
|
-
|
|
112
|
+
# @return [Hash, Array, LLM::Object, nil]
|
|
113
|
+
attr_reader :arguments
|
|
114
|
+
|
|
115
|
+
##
|
|
116
|
+
# Sets function arguments, wrapping them in an LLM::Object
|
|
117
|
+
# @param [Hash, LLM::Object] other
|
|
118
|
+
# @return [void]
|
|
119
|
+
def arguments=(other)
|
|
120
|
+
@arguments = LLM::Object.from(other)
|
|
121
|
+
end
|
|
114
122
|
|
|
115
123
|
##
|
|
116
124
|
# Returns a tracer, or nil
|
|
@@ -373,10 +381,10 @@ class LLM::Function
|
|
|
373
381
|
# Returns a Return object with either the function result or error information.
|
|
374
382
|
def call_function
|
|
375
383
|
runner = self.runner
|
|
376
|
-
kwargs =
|
|
384
|
+
kwargs = arguments.respond_to?(:to_h) ? arguments.to_h.transform_keys(&:to_sym) : arguments
|
|
377
385
|
Return.new(id, name, runner.call(**kwargs))
|
|
378
386
|
rescue => ex
|
|
379
|
-
Return.new(id, name,
|
|
387
|
+
Return.new(id, name, {error: true, type: ex.class.name, message: ex.message})
|
|
380
388
|
end
|
|
381
389
|
|
|
382
390
|
def call!
|
data/lib/llm/object/builder.rb
CHANGED
data/lib/llm/object.rb
CHANGED
|
@@ -184,6 +184,15 @@ class LLM::Object < BasicObject
|
|
|
184
184
|
@h.slice(*args)
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
+
##
|
|
188
|
+
# @param [Hash, #to_h] other
|
|
189
|
+
# @return [Boolean]
|
|
190
|
+
def ==(other)
|
|
191
|
+
return false unless other.respond_to?(:to_h)
|
|
192
|
+
to_h == other.to_h || to_hash == other.to_h
|
|
193
|
+
end
|
|
194
|
+
alias_method :eql?, :==
|
|
195
|
+
|
|
187
196
|
private
|
|
188
197
|
|
|
189
198
|
def method_missing(m, *args, &b)
|
data/lib/llm/schema.rb
CHANGED
|
@@ -20,14 +20,16 @@
|
|
|
20
20
|
#
|
|
21
21
|
# @example Ruby-style
|
|
22
22
|
# class Address < LLM::Schema
|
|
23
|
-
# property :street, String, "Street address"
|
|
23
|
+
# property :street, String, "Street address"
|
|
24
|
+
# required %i[street]
|
|
24
25
|
# end
|
|
25
26
|
#
|
|
26
27
|
# class Person < LLM::Schema
|
|
27
|
-
# property :name, String, "Person's name"
|
|
28
|
-
# property :age, Integer, "Person's age"
|
|
29
|
-
# property :hobbies, Array[String], "Person's hobbies"
|
|
30
|
-
# property :address, Address, "Person's address"
|
|
28
|
+
# property :name, String, "Person's name"
|
|
29
|
+
# property :age, Integer, "Person's age"
|
|
30
|
+
# property :hobbies, Array[String], "Person's hobbies"
|
|
31
|
+
# property :address, Address, "Person's address"
|
|
32
|
+
# required %i[name age hobbies address]
|
|
31
33
|
# end
|
|
32
34
|
class LLM::Schema
|
|
33
35
|
require_relative "schema/version"
|
|
@@ -74,6 +76,10 @@ class LLM::Schema
|
|
|
74
76
|
end
|
|
75
77
|
schema.array(item)
|
|
76
78
|
end
|
|
79
|
+
|
|
80
|
+
def fetch(properties, name)
|
|
81
|
+
properties[name] || properties.fetch(name.to_s)
|
|
82
|
+
end
|
|
77
83
|
end
|
|
78
84
|
|
|
79
85
|
##
|
|
@@ -103,6 +109,18 @@ class LLM::Schema
|
|
|
103
109
|
end
|
|
104
110
|
end
|
|
105
111
|
|
|
112
|
+
##
|
|
113
|
+
# Mark existing properties as required.
|
|
114
|
+
# @param names [Array<Symbol,String>]
|
|
115
|
+
# @return [LLM::Schema::Object]
|
|
116
|
+
def self.required(names)
|
|
117
|
+
lock do
|
|
118
|
+
object.tap do |schema|
|
|
119
|
+
[*names].each { Utils.fetch(schema.properties, _1).required }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
106
124
|
##
|
|
107
125
|
# @api private
|
|
108
126
|
# @return [LLM::Schema]
|
data/lib/llm/skill.rb
CHANGED
|
@@ -56,6 +56,7 @@ module LLM
|
|
|
56
56
|
@instructions = ""
|
|
57
57
|
@frontmatter = LLM::Object.from({})
|
|
58
58
|
@tools = []
|
|
59
|
+
@inherit_tools = false
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
##
|
|
@@ -74,18 +75,8 @@ module LLM
|
|
|
74
75
|
# @param [LLM::Context] ctx
|
|
75
76
|
# @return [Hash]
|
|
76
77
|
def call(ctx)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
concurrency = params[:stream].extra[:concurrency] if LLM::Stream === params[:stream]
|
|
80
|
-
params[:concurrency] = concurrency if concurrency
|
|
81
|
-
agent = Class.new(LLM::Agent) do
|
|
82
|
-
instructions(instructions)
|
|
83
|
-
tools(*tools)
|
|
84
|
-
tracer(tracer)
|
|
85
|
-
end.new(ctx.llm, params)
|
|
86
|
-
agent.messages.concat(messages_for(ctx))
|
|
87
|
-
res = agent.talk("Solve the user's query.")
|
|
88
|
-
{content: res.content}
|
|
78
|
+
content = agent(ctx).talk("Solve the user's query.").content
|
|
79
|
+
{content:}
|
|
89
80
|
end
|
|
90
81
|
|
|
91
82
|
##
|
|
@@ -96,9 +87,10 @@ module LLM
|
|
|
96
87
|
def to_tool(ctx)
|
|
97
88
|
skill = self
|
|
98
89
|
Class.new(LLM::Tool) do
|
|
90
|
+
attr_accessor :tracer
|
|
91
|
+
|
|
99
92
|
name skill.name
|
|
100
93
|
description skill.description
|
|
101
|
-
attr_accessor :tracer
|
|
102
94
|
|
|
103
95
|
define_singleton_method(:skill?) do
|
|
104
96
|
true
|
|
@@ -110,6 +102,13 @@ module LLM
|
|
|
110
102
|
end
|
|
111
103
|
end
|
|
112
104
|
|
|
105
|
+
##
|
|
106
|
+
# Returns true when a skill should inherit tools from its parent
|
|
107
|
+
# @return [Boolean]
|
|
108
|
+
def inherit_tools?
|
|
109
|
+
@inherit_tools
|
|
110
|
+
end
|
|
111
|
+
|
|
113
112
|
private
|
|
114
113
|
|
|
115
114
|
def messages_for(ctx)
|
|
@@ -132,8 +131,39 @@ module LLM
|
|
|
132
131
|
@frontmatter = LLM::Object.from(YAML.safe_load(match[1]) || {})
|
|
133
132
|
@name = @frontmatter.name || @name
|
|
134
133
|
@description = @frontmatter.description || @description
|
|
135
|
-
@tools = [*@frontmatter.tools].map { LLM::Tool.find_by_name!(_1) }
|
|
136
134
|
@instructions = match[2]
|
|
135
|
+
@inherit_tools, @tools = parse_tools(@frontmatter.tools)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def parse_tools(tools)
|
|
139
|
+
case tools
|
|
140
|
+
when String
|
|
141
|
+
tools == "inherit" ? [true, []] : raise_invalid_error!(tools)
|
|
142
|
+
when Array
|
|
143
|
+
[false, [*@frontmatter.tools].map { LLM::Tool.find_by_name!(_1) }]
|
|
144
|
+
when NilClass
|
|
145
|
+
[false, []]
|
|
146
|
+
else
|
|
147
|
+
raise_invalid_error!(tools)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def raise_invalid_error!(tools)
|
|
152
|
+
raise LLM::Error, "invalid value for tools key: '#{tools}'"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def agent(ctx)
|
|
156
|
+
instructions, tools, tracer, inherit_tools = self.instructions, self.tools, ctx.llm.tracer, inherit_tools?
|
|
157
|
+
params = ctx.params.merge(mode: ctx.mode).reject { [:tools, :schema].include?(_1) }
|
|
158
|
+
concurrency = params[:stream].extra[:concurrency] if LLM::Stream === params[:stream]
|
|
159
|
+
params[:concurrency] = concurrency if concurrency
|
|
160
|
+
agent = Class.new(LLM::Agent) do
|
|
161
|
+
instructions(instructions)
|
|
162
|
+
tools(inherit_tools ? ctx.params[:tools] : tools)
|
|
163
|
+
tracer(tracer)
|
|
164
|
+
end.new(ctx.llm, params)
|
|
165
|
+
agent.messages.concat(messages_for(ctx))
|
|
166
|
+
agent
|
|
137
167
|
end
|
|
138
168
|
end
|
|
139
169
|
end
|
data/lib/llm/tracer/telemetry.rb
CHANGED
|
@@ -223,7 +223,9 @@ module LLM
|
|
|
223
223
|
require "opentelemetry/sdk" unless defined?(OpenTelemetry)
|
|
224
224
|
@exporter ||= OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new
|
|
225
225
|
processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(@exporter)
|
|
226
|
-
@tracer_provider = OpenTelemetry::SDK::Trace::TracerProvider.new
|
|
226
|
+
@tracer_provider = OpenTelemetry::SDK::Trace::TracerProvider.new(
|
|
227
|
+
sampler: OpenTelemetry::SDK::Trace::Samplers::ALWAYS_ON
|
|
228
|
+
)
|
|
227
229
|
@tracer_provider.add_span_processor(processor)
|
|
228
230
|
@tracer = @tracer_provider.tracer("llm.rb", LLM::VERSION)
|
|
229
231
|
end
|
data/lib/llm/version.rb
CHANGED