Class: RubyCode::Memory
Overview
Manages conversation memory using shared database connection
Class Method Summary
collapse
Instance Method Summary
collapse
-
#add_message(message = nil, role: nil, content: nil, tool_calls: nil) ⇒ Object
Accept either Message objects or keyword arguments for backwards compatibility.
-
#build_message_list(first_msg, middle, recent, prune_tool_results) ⇒ Object
-
#build_windowed_format(all_messages, window_size, prune_tool_results) ⇒ Object
-
#clear ⇒ Object
-
#last_assistant_message ⇒ Object
-
#last_user_message ⇒ Object
-
#messages ⇒ Object
-
#partition_messages(all_messages, window_size) ⇒ Object
-
#prune_tool_results_from_middle(middle) ⇒ Object
-
#should_prune_middle?(prune_tool_results, middle) ⇒ Boolean
-
#to_llm_format(window_size: 10, prune_tool_results: true) ⇒ Object
-
#tool_result_message?(message) ⇒ Boolean
all, count, dataset, delete, first, last, latest, oldest, order, where
Class Method Details
.table_name ⇒ Object
7
8
9
|
# File 'lib/rubycode/models/memory.rb', line 7
def table_name
:messages
end
|
Instance Method Details
#add_message(message = nil, role: nil, content: nil, tool_calls: nil) ⇒ Object
Accept either Message objects or keyword arguments for backwards compatibility
13
14
15
16
17
18
19
20
21
|
# File 'lib/rubycode/models/memory.rb', line 13
def add_message(message = nil, role: nil, content: nil, tool_calls: nil)
if message.is_a?(Message)
insert_message(message.role, message.content, message.tool_calls)
elsif role && content
insert_message(role, content, tool_calls)
else
raise ArgumentError, "Must provide either a Message object or role: and content: keyword arguments"
end
end
|
#build_message_list(first_msg, middle, recent, prune_tool_results) ⇒ Object
49
50
51
52
53
54
|
# File 'lib/rubycode/models/memory.rb', line 49
def build_message_list(first_msg, middle, recent, prune_tool_results)
return [first_msg] + recent unless should_prune_middle?(prune_tool_results, middle)
pruned_middle = prune_tool_results_from_middle(middle)
[first_msg] + pruned_middle + recent
end
|
40
41
42
43
44
45
46
47
|
# File 'lib/rubycode/models/memory.rb', line 40
def build_windowed_format(all_messages, window_size, prune_tool_results)
first_msg, recent, middle = partition_messages(all_messages, window_size)
return recent.map(&:to_h) if recent.include?(first_msg)
result_messages = build_message_list(first_msg, middle, recent, prune_tool_results)
result_messages.map(&:to_h)
end
|
#clear ⇒ Object
81
82
83
|
# File 'lib/rubycode/models/memory.rb', line 81
def clear
db[:messages].delete
end
|
#last_assistant_message ⇒ Object
96
97
98
99
100
101
102
103
104
105
|
# File 'lib/rubycode/models/memory.rb', line 96
def last_assistant_message
row = self.class.latest.where(role: "assistant").first
return nil unless row
Message.new(
role: row[:role],
content: row[:content],
tool_calls: deserialize_tool_calls(row[:tool_calls])
)
end
|
#last_user_message ⇒ Object
85
86
87
88
89
90
91
92
93
94
|
# File 'lib/rubycode/models/memory.rb', line 85
def last_user_message
row = self.class.latest.where(role: "user").first
return nil unless row
Message.new(
role: row[:role],
content: row[:content],
tool_calls: deserialize_tool_calls(row[:tool_calls])
)
end
|
#messages ⇒ Object
23
24
25
26
27
28
29
30
31
|
# File 'lib/rubycode/models/memory.rb', line 23
def messages
db[:messages].order(:id).map do |row|
Message.new(
role: row[:role],
content: row[:content],
tool_calls: deserialize_tool_calls(row[:tool_calls])
)
end
end
|
#partition_messages(all_messages, window_size) ⇒ Object
56
57
58
59
60
61
|
# File 'lib/rubycode/models/memory.rb', line 56
def partition_messages(all_messages, window_size)
first_msg = all_messages.first
recent = all_messages.last(window_size)
middle = all_messages[1..-(window_size + 1)] || []
[first_msg, recent, middle]
end
|
71
72
73
74
75
76
77
78
79
|
# File 'lib/rubycode/models/memory.rb', line 71
def prune_tool_results_from_middle(middle)
middle.map do |msg|
if tool_result_message?(msg)
Message.new(role: msg.role, content: "[Tool result cleared]")
else
msg
end
end
end
|
#should_prune_middle?(prune_tool_results, middle) ⇒ Boolean
63
64
65
|
# File 'lib/rubycode/models/memory.rb', line 63
def should_prune_middle?(prune_tool_results, middle)
prune_tool_results && middle.any? { |msg| tool_result_message?(msg) }
end
|
33
34
35
36
37
38
|
# File 'lib/rubycode/models/memory.rb', line 33
def to_llm_format(window_size: 10, prune_tool_results: true)
all_messages = messages
return all_messages.map(&:to_h) if all_messages.length <= window_size
build_windowed_format(all_messages, window_size, prune_tool_results)
end
|
67
68
69
|
# File 'lib/rubycode/models/memory.rb', line 67
def tool_result_message?(message)
message.role == "user" && message.content.start_with?("Tool '")
end
|