ruby_llm 0.1.0.pre17 → 0.1.0.pre19
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/README.md +23 -5
- data/lib/ruby_llm/active_record/acts_as.rb +77 -17
- data/lib/ruby_llm/chat.rb +3 -1
- data/lib/ruby_llm/tool_call.rb +8 -0
- data/lib/ruby_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: 230db2439975e0515e1f128a286222c06de3de1b7eff0b77631bc9e4fa2df338
|
4
|
+
data.tar.gz: 25846959e0c3d2c411d82825077b4ff112bef0aea7910e87f5b3336fd58f8dca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b082f5426e1c0d4ef426df99c5cca9463943b525e113b11aa9d60b799ebe6b0ae77fcc347a06d922b98316b402f8eb9a6a716ddd5e45c26ef86458eb4405d17c
|
7
|
+
data.tar.gz: c8a8a42ef3e0e8eb676fae0a28a26103c0dd1ff66be9753bb13d448f3114fb05d862fe78eee5f7599b6e2edd28a8d78c4e1fcd64ca87e163cecf1725f73351ff
|
data/README.md
CHANGED
@@ -82,7 +82,7 @@ Need vector embeddings for your text? RubyLLM makes it simple:
|
|
82
82
|
|
83
83
|
```ruby
|
84
84
|
# Get embeddings with the default model
|
85
|
-
vector = RubyLLM.embed
|
85
|
+
vector = RubyLLM.embed "Hello, world!"
|
86
86
|
|
87
87
|
# Use a specific model
|
88
88
|
vector = RubyLLM.embed(
|
@@ -191,18 +191,32 @@ end
|
|
191
191
|
class CreateMessages < ActiveRecord::Migration[8.0]
|
192
192
|
def change
|
193
193
|
create_table :messages do |t|
|
194
|
-
t.references :chat
|
194
|
+
t.references :chat, null: false
|
195
195
|
t.string :role
|
196
196
|
t.text :content
|
197
|
-
t.
|
198
|
-
t.string :tool_call_id
|
197
|
+
t.string :model_id
|
199
198
|
t.integer :input_tokens
|
200
199
|
t.integer :output_tokens
|
201
|
-
t.
|
200
|
+
t.references :tool_call
|
202
201
|
t.timestamps
|
203
202
|
end
|
204
203
|
end
|
205
204
|
end
|
205
|
+
|
206
|
+
# db/migrate/YYYYMMDDHHMMSS_create_tool_calls.rb
|
207
|
+
class CreateToolCalls < ActiveRecord::Migration[8.0]
|
208
|
+
def change
|
209
|
+
create_table :tool_calls do |t|
|
210
|
+
t.references :message, null: false
|
211
|
+
t.string :tool_call_id, null: false
|
212
|
+
t.string :name, null: false
|
213
|
+
t.jsonb :arguments, default: {}
|
214
|
+
t.timestamps
|
215
|
+
end
|
216
|
+
|
217
|
+
add_index :tool_calls, :tool_call_id
|
218
|
+
end
|
219
|
+
end
|
206
220
|
```
|
207
221
|
|
208
222
|
Then in your models:
|
@@ -218,6 +232,10 @@ end
|
|
218
232
|
class Message < ApplicationRecord
|
219
233
|
acts_as_message
|
220
234
|
end
|
235
|
+
|
236
|
+
class ToolCall < ApplicationRecord
|
237
|
+
acts_as_tool_call
|
238
|
+
end
|
221
239
|
```
|
222
240
|
|
223
241
|
That's it! Now you can use chats straight from your models:
|
@@ -8,13 +8,16 @@ module RubyLLM
|
|
8
8
|
module ActsAs
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
|
-
class_methods do
|
12
|
-
def acts_as_chat(message_class: 'Message') # rubocop:disable Metrics/MethodLength
|
11
|
+
class_methods do # rubocop:disable Metrics/BlockLength
|
12
|
+
def acts_as_chat(message_class: 'Message', tool_call_class: 'ToolCall') # rubocop:disable Metrics/MethodLength
|
13
13
|
include ChatMethods
|
14
14
|
|
15
|
+
@message_class = message_class.to_s
|
16
|
+
@tool_call_class = tool_call_class.to_s
|
17
|
+
|
15
18
|
has_many :messages,
|
16
19
|
-> { order(created_at: :asc) },
|
17
|
-
class_name: message_class
|
20
|
+
class_name: @message_class,
|
18
21
|
dependent: :destroy
|
19
22
|
|
20
23
|
delegate :complete,
|
@@ -28,13 +31,35 @@ module RubyLLM
|
|
28
31
|
to: :to_llm
|
29
32
|
end
|
30
33
|
|
31
|
-
def acts_as_message(chat_class: 'Chat')
|
34
|
+
def acts_as_message(chat_class: 'Chat', tool_call_class: 'ToolCall') # rubocop:disable Metrics/MethodLength
|
32
35
|
include MessageMethods
|
33
36
|
|
34
|
-
|
37
|
+
@chat_class = chat_class.to_s
|
38
|
+
@tool_call_class = tool_call_class.to_s
|
39
|
+
|
40
|
+
belongs_to :chat, class_name: @chat_class
|
41
|
+
has_many :tool_calls, class_name: @tool_call_class, dependent: :destroy
|
42
|
+
|
43
|
+
belongs_to :parent_tool_call,
|
44
|
+
class_name: @tool_call_class,
|
45
|
+
foreign_key: 'tool_call_id',
|
46
|
+
optional: true,
|
47
|
+
inverse_of: :result
|
35
48
|
|
36
49
|
delegate :tool_call?, :tool_result?, :tool_results, to: :to_llm
|
37
50
|
end
|
51
|
+
|
52
|
+
def acts_as_tool_call(message_class: 'Message')
|
53
|
+
@message_class = message_class.to_s
|
54
|
+
|
55
|
+
belongs_to :message, class_name: @message_class
|
56
|
+
|
57
|
+
has_one :result,
|
58
|
+
class_name: @message_class,
|
59
|
+
foreign_key: 'tool_call_id',
|
60
|
+
inverse_of: :parent_tool_call,
|
61
|
+
dependent: :nullify
|
62
|
+
end
|
38
63
|
end
|
39
64
|
end
|
40
65
|
|
@@ -43,6 +68,10 @@ module RubyLLM
|
|
43
68
|
module ChatMethods
|
44
69
|
extend ActiveSupport::Concern
|
45
70
|
|
71
|
+
class_methods do
|
72
|
+
attr_reader :tool_call_class
|
73
|
+
end
|
74
|
+
|
46
75
|
def to_llm
|
47
76
|
chat = RubyLLM.chat(model: model_id)
|
48
77
|
|
@@ -73,18 +102,32 @@ module RubyLLM
|
|
73
102
|
)
|
74
103
|
end
|
75
104
|
|
76
|
-
def persist_message_completion(message)
|
105
|
+
def persist_message_completion(message) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
77
106
|
return unless message
|
78
107
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
108
|
+
if message.tool_call_id
|
109
|
+
tool_call_id = self.class.tool_call_class.constantize.find_by(tool_call_id: message.tool_call_id).id
|
110
|
+
end
|
111
|
+
|
112
|
+
transaction do
|
113
|
+
messages.last.update!(
|
114
|
+
role: message.role,
|
115
|
+
content: message.content,
|
116
|
+
model_id: message.model_id,
|
117
|
+
tool_call_id: tool_call_id,
|
118
|
+
input_tokens: message.input_tokens,
|
119
|
+
output_tokens: message.output_tokens
|
120
|
+
)
|
121
|
+
persist_tool_calls(message.tool_calls) if message.tool_calls.present?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def persist_tool_calls(tool_calls)
|
126
|
+
tool_calls.each_value do |tool_call|
|
127
|
+
attributes = tool_call.to_h
|
128
|
+
attributes[:tool_call_id] = attributes.delete(:id)
|
129
|
+
messages.last.tool_calls.create!(**attributes)
|
130
|
+
end
|
88
131
|
end
|
89
132
|
end
|
90
133
|
|
@@ -97,13 +140,30 @@ module RubyLLM
|
|
97
140
|
RubyLLM::Message.new(
|
98
141
|
role: role.to_sym,
|
99
142
|
content: content,
|
100
|
-
tool_calls:
|
101
|
-
tool_call_id:
|
143
|
+
tool_calls: extract_tool_calls,
|
144
|
+
tool_call_id: extract_tool_call_id,
|
102
145
|
input_tokens: input_tokens,
|
103
146
|
output_tokens: output_tokens,
|
104
147
|
model_id: model_id
|
105
148
|
)
|
106
149
|
end
|
150
|
+
|
151
|
+
def extract_tool_calls
|
152
|
+
tool_calls.to_h do |tool_call|
|
153
|
+
[
|
154
|
+
tool_call.tool_call_id,
|
155
|
+
RubyLLM::ToolCall.new(
|
156
|
+
id: tool_call.tool_call_id,
|
157
|
+
name: tool_call.name,
|
158
|
+
arguments: tool_call.arguments
|
159
|
+
)
|
160
|
+
]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def extract_tool_call_id
|
165
|
+
parent_tool_call&.tool_call_id
|
166
|
+
end
|
107
167
|
end
|
108
168
|
end
|
109
169
|
end
|
data/lib/ruby_llm/chat.rb
CHANGED
@@ -97,8 +97,10 @@ module RubyLLM
|
|
97
97
|
|
98
98
|
def handle_tool_calls(response, &block)
|
99
99
|
response.tool_calls.each_value do |tool_call|
|
100
|
+
@on[:new_message]&.call
|
100
101
|
result = execute_tool tool_call
|
101
|
-
add_tool_result tool_call.id, result
|
102
|
+
message = add_tool_result tool_call.id, result
|
103
|
+
@on[:end_message]&.call(message)
|
102
104
|
end
|
103
105
|
|
104
106
|
complete(&block)
|
data/lib/ruby_llm/tool_call.rb
CHANGED
data/lib/ruby_llm/version.rb
CHANGED