llmemory 0.1.12 → 0.1.13
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 +5 -0
- data/lib/llmemory/configuration.rb +3 -1
- data/lib/llmemory/memory.rb +65 -0
- data/lib/llmemory/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: a188251e04aac90f929fcc952f7902a8e9b86728742ab88e5f209953821efd30
|
|
4
|
+
data.tar.gz: 01f3cd9d68c50a1a52ed33683b973a379073890db1ae5a3073676fd598581eca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e24d411ffaca985dc360bc6a6d271f8fd57c687cef26c8242e047fab6bcda400b3764b78aeea8d58ec253bc33ce48b89a46d6a8bdb71db8152c4d175880f3b87
|
|
7
|
+
data.tar.gz: d7097e4c6cc8442088f5adb0614015b8d9d0541db8f4843e729c8e94cfefe0faf49969e9abb75381b070386c53623631b937fc72989a1f7cb0aa27b3b45a9171
|
data/README.md
CHANGED
|
@@ -33,6 +33,9 @@ context = memory.retrieve("¿Qué preferencias tiene el usuario?", max_tokens: 2
|
|
|
33
33
|
# Optionally consolidate current conversation into long-term (extract facts)
|
|
34
34
|
memory.consolidate!
|
|
35
35
|
|
|
36
|
+
# Compact short-term memory when it gets too large (summarizes old messages)
|
|
37
|
+
memory.compact!(max_bytes: 8192) # or use config default
|
|
38
|
+
|
|
36
39
|
# Clear session (short-term) while keeping long-term intact
|
|
37
40
|
memory.clear_session!
|
|
38
41
|
```
|
|
@@ -41,6 +44,7 @@ memory.clear_session!
|
|
|
41
44
|
- **`messages`** — Returns the current conversation history.
|
|
42
45
|
- **`retrieve(query, max_tokens: nil)`** — Returns combined context: recent conversation + relevant long-term memories.
|
|
43
46
|
- **`consolidate!`** — Extracts facts from the current conversation and stores them in long-term.
|
|
47
|
+
- **`compact!(max_bytes: nil)`** — Compacts short-term memory by summarizing old messages when byte size exceeds limit. Uses LLM to create a summary, keeping recent messages intact.
|
|
44
48
|
- **`clear_session!`** — Clears short-term only.
|
|
45
49
|
|
|
46
50
|
## Configuration
|
|
@@ -59,6 +63,7 @@ Llmemory.configure do |config|
|
|
|
59
63
|
config.time_decay_half_life_days = 30
|
|
60
64
|
config.max_retrieval_tokens = 2000
|
|
61
65
|
config.prune_after_days = 90
|
|
66
|
+
config.compact_max_bytes = 8192 # max bytes before compact! triggers
|
|
62
67
|
end
|
|
63
68
|
```
|
|
64
69
|
|
|
@@ -15,7 +15,8 @@ module Llmemory
|
|
|
15
15
|
:vector_store,
|
|
16
16
|
:time_decay_half_life_days,
|
|
17
17
|
:max_retrieval_tokens,
|
|
18
|
-
:prune_after_days
|
|
18
|
+
:prune_after_days,
|
|
19
|
+
:compact_max_bytes
|
|
19
20
|
|
|
20
21
|
def initialize
|
|
21
22
|
@llm_provider = :openai
|
|
@@ -32,6 +33,7 @@ module Llmemory
|
|
|
32
33
|
@time_decay_half_life_days = 30
|
|
33
34
|
@max_retrieval_tokens = 2000
|
|
34
35
|
@prune_after_days = 90
|
|
36
|
+
@compact_max_bytes = 8192
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
|
data/lib/llmemory/memory.rb
CHANGED
|
@@ -52,12 +52,77 @@ module Llmemory
|
|
|
52
52
|
true
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def compact!(max_bytes: nil)
|
|
56
|
+
max = max_bytes || Llmemory.configuration.compact_max_bytes
|
|
57
|
+
msgs = messages
|
|
58
|
+
current_bytes = messages_byte_size(msgs)
|
|
59
|
+
return false if current_bytes <= max
|
|
60
|
+
|
|
61
|
+
old_msgs, recent_msgs = split_messages_by_bytes(msgs, max)
|
|
62
|
+
return false if old_msgs.empty?
|
|
63
|
+
|
|
64
|
+
summary = summarize_messages(old_msgs)
|
|
65
|
+
compacted = [{ role: :system, content: summary }] + recent_msgs
|
|
66
|
+
save_state(messages: compacted)
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
|
|
55
70
|
def user_id
|
|
56
71
|
@user_id
|
|
57
72
|
end
|
|
58
73
|
|
|
59
74
|
private
|
|
60
75
|
|
|
76
|
+
def summarize_messages(msgs)
|
|
77
|
+
conversation = msgs.map { |m| format_message(m) }.join("\n")
|
|
78
|
+
prompt = <<~PROMPT
|
|
79
|
+
Summarize the following conversation into a concise summary that preserves key information, decisions, and context. Write it as a brief narrative (max 200 words).
|
|
80
|
+
|
|
81
|
+
Conversation:
|
|
82
|
+
#{conversation}
|
|
83
|
+
|
|
84
|
+
Summary:
|
|
85
|
+
PROMPT
|
|
86
|
+
llm_client.invoke(prompt.strip).to_s.strip
|
|
87
|
+
rescue Llmemory::LLMError
|
|
88
|
+
msgs.map { |m| format_message(m) }.join("\n")[0..500]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def llm_client
|
|
92
|
+
@llm ||= Llmemory::LLM.client
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def messages_byte_size(msgs)
|
|
96
|
+
msgs.sum { |m| message_byte_size(m) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def message_byte_size(msg)
|
|
100
|
+
role = msg[:role] || msg["role"]
|
|
101
|
+
content = msg[:content] || msg["content"]
|
|
102
|
+
role.to_s.bytesize + content.to_s.bytesize
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def split_messages_by_bytes(msgs, max_bytes)
|
|
106
|
+
target_recent_bytes = max_bytes / 2
|
|
107
|
+
recent_bytes = 0
|
|
108
|
+
split_index = msgs.size
|
|
109
|
+
|
|
110
|
+
(msgs.size - 1).downto(0) do |i|
|
|
111
|
+
msg_bytes = message_byte_size(msgs[i])
|
|
112
|
+
if recent_bytes + msg_bytes <= target_recent_bytes
|
|
113
|
+
recent_bytes += msg_bytes
|
|
114
|
+
split_index = i
|
|
115
|
+
else
|
|
116
|
+
break
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
split_index = [split_index, msgs.size - 1].min
|
|
121
|
+
split_index = [split_index, 1].max if msgs.size > 1
|
|
122
|
+
|
|
123
|
+
[msgs[0...split_index], msgs[split_index..]]
|
|
124
|
+
end
|
|
125
|
+
|
|
61
126
|
def build_long_term(long_term_type)
|
|
62
127
|
llm_opts = @llm ? { llm: @llm } : {}
|
|
63
128
|
case long_term_type.to_s.to_sym
|
data/lib/llmemory/version.rb
CHANGED