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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33ff7cbff0694be426fa937233f3429688759f595e7522a0bc3c22aa9dcb6214
4
- data.tar.gz: 53ccabdcd6706037e63574bf97cd575bf5310c1cde96dd794e83d38ec0ed3606
3
+ metadata.gz: a188251e04aac90f929fcc952f7902a8e9b86728742ab88e5f209953821efd30
4
+ data.tar.gz: 01f3cd9d68c50a1a52ed33683b973a379073890db1ae5a3073676fd598581eca
5
5
  SHA512:
6
- metadata.gz: 463b3028747f9ff47b9949325d7461b41ad231c0798801269b0f083c96455eb347714f6fc6fb5e96fdede30897b8753e46d514944f2ecf3fc097ccd719b637e1
7
- data.tar.gz: dcd0da448d5b2ad4e686552b7cb9271fac36b58882cf3fd97761effde76851f4c193b1edbc8f50e46f1289499b4fe2c24cb06f6ba3093cab6a8e731982e60225
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
 
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Llmemory
4
- VERSION = "0.1.12"
4
+ VERSION = "0.1.13"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llmemory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - llmemory