Class: Mana::Memory

Inherits:
Object
  • Object
show all
Defined in:
lib/mana/memory.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMemory

Initialize with empty short-term and load persisted long-term memories from disk



8
9
10
11
12
13
14
# File 'lib/mana/memory.rb', line 8

def initialize
  @short_term = []
  @long_term = []
  @summaries = []
  @next_id = 1
  load_long_term
end

Instance Attribute Details

#long_termObject (readonly)

Returns the value of attribute long_term.



5
6
7
# File 'lib/mana/memory.rb', line 5

def long_term
  @long_term
end

#short_termObject (readonly)

Returns the value of attribute short_term.



5
6
7
# File 'lib/mana/memory.rb', line 5

def short_term
  @short_term
end

#summariesObject (readonly)

Returns the value of attribute summaries.



5
6
7
# File 'lib/mana/memory.rb', line 5

def summaries
  @summaries
end

Class Method Details

.currentObject

Return the current thread's memory instance (lazy-initialized). Uses config.memory_class if set (e.g. Claw::Memory), otherwise Mana::Memory. Returns nil in incognito mode.



22
23
24
25
26
27
28
29
# File 'lib/mana/memory.rb', line 22

def current
  return nil if incognito?

  Thread.current[:mana_memory] ||= begin
    klass = Mana.config.memory_class || self
    klass.new
  end
end

.incognito(&block) ⇒ Object

Run a block with memory disabled. Saves and restores previous state.



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/mana/memory.rb', line 37

def incognito(&block)
  previous_memory = Thread.current[:mana_memory]
  previous_incognito = Thread.current[:mana_incognito]
  Thread.current[:mana_incognito] = true
  Thread.current[:mana_memory] = nil
  block.call
# Always restore previous state, even if the block raises
ensure
  Thread.current[:mana_incognito] = previous_incognito
  Thread.current[:mana_memory] = previous_memory
end

.incognito?Boolean

Check if the current thread is in incognito mode (no memory)

Returns:

  • (Boolean)


32
33
34
# File 'lib/mana/memory.rb', line 32

def incognito?
  Thread.current[:mana_incognito] == true
end

Instance Method Details

#clear!Object

Clear both short-term and long-term memory



83
84
85
86
# File 'lib/mana/memory.rb', line 83

def clear!
  clear_short_term!
  clear_long_term!
end

#clear_long_term!Object

Clear persistent memories from both in-memory array and disk



95
96
97
98
# File 'lib/mana/memory.rb', line 95

def clear_long_term!
  @long_term.clear
  store.clear(namespace)
end

#clear_short_term!Object

Clear conversation history and compaction summaries



89
90
91
92
# File 'lib/mana/memory.rb', line 89

def clear_short_term!
  @short_term.clear
  @summaries.clear
end

#estimate_tokens(text) ⇒ Object

Rough token estimate: ~4 characters per token



74
75
76
77
78
# File 'lib/mana/memory.rb', line 74

def estimate_tokens(text)
  return 0 unless text.is_a?(String)

  (text.length / 4.0).ceil
end

#forget(id:) ⇒ Object

Remove a specific long-term memory by ID and persist the change



101
102
103
104
# File 'lib/mana/memory.rb', line 101

def forget(id:)
  @long_term.reject! { |m| m[:id] == id }
  store.write(namespace, @long_term)
end

#inspectObject

Human-readable summary: counts and token usage



123
124
125
# File 'lib/mana/memory.rb', line 123

def inspect
  "#<Mana::Memory long_term=#{@long_term.size}, short_term=#{short_term_rounds} rounds, tokens=#{token_count}/#{context_window}>"
end

#remember(content) ⇒ Object

Store a fact in long-term memory. Deduplicates by content. Persists to disk immediately after adding.



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/mana/memory.rb', line 108

def remember(content)
  # Deduplicate: skip if identical content already exists
  existing = @long_term.find { |e| e[:content] == content }
  return existing if existing

  entry = { id: @next_id, content: content, created_at: Time.now.iso8601 }
  @next_id += 1
  @long_term << entry
  store.write(namespace, @long_term)
  entry
end

#token_countObject

Estimate total token count across short-term messages, long-term facts, and summaries.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/mana/memory.rb', line 53

def token_count
  count = 0
  @short_term.each do |msg|
    content = msg[:content]
    case content
    when String
      # Plain text message
      count += estimate_tokens(content)
    when Array
      # Array of content blocks (tool_use, tool_result, text)
      content.each do |block|
        count += estimate_tokens(block[:text] || block[:content] || "")
      end
    end
  end
  @long_term.each { |m| count += estimate_tokens(m[:content]) }
  @summaries.each { |s| count += estimate_tokens(s) }
  count
end