lex-agentic-memory 0.1.0 → 0.1.2
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/CHANGELOG.md +12 -1
- data/README.md +48 -3
- data/lex-agentic-memory.gemspec +2 -0
- data/lib/legion/extensions/agentic/memory/semantic_priming/helpers/priming_network.rb +2 -0
- data/lib/legion/extensions/agentic/memory/semantic_priming/version.rb +1 -1
- data/lib/legion/extensions/agentic/memory/trace/helpers/snapshot.rb +145 -0
- data/lib/legion/extensions/agentic/memory/version.rb +1 -1
- data/lib/legion/extensions/agentic/memory.rb +42 -0
- data/spec/legion/extensions/agentic/memory/echo/cognitive_echo_spec.rb +1 -1
- data/spec/legion/extensions/agentic/memory/episodic/episodic_buffer_spec.rb +2 -2
- data/spec/legion/extensions/agentic/memory/gaia_hooks_spec.rb +14 -0
- data/spec/legion/extensions/agentic/memory/hologram/cognitive_hologram_spec.rb +1 -1
- data/spec/legion/extensions/agentic/memory/immune_memory/cognitive_immune_memory_spec.rb +1 -1
- data/spec/legion/extensions/agentic/memory/semantic_priming/helpers/priming_network_spec.rb +12 -0
- data/spec/legion/extensions/agentic/memory/semantic_priming/semantic_priming_spec.rb +1 -1
- data/spec/legion/extensions/agentic/memory/trace/helpers/snapshot_spec.rb +87 -0
- metadata +18 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a4e4cd5cb55b0bcb654b44c0db73ee734142186f9644301e69abe95edee2ddb
|
|
4
|
+
data.tar.gz: 935663fa7f445a49611f707e83c8de9519822ef28492664e23fba71f4d82af20
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19a3751371051af37741c3907832b1f2558912ab508a52ce72c2e47e1045ea207a56abcbc2a1ad6d546f72b8e6de4cedc9a6c3c8ab968df27afc51866dd60aca
|
|
7
|
+
data.tar.gz: 2406cc17b24e58554824439d78d578e07b5d13e3a8b63bcd701dacb2f751f82d94c6c79e35030e8af610304aab09cb4020bb92654c1106b1ac171bfe781872ac
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.1.2] - 2026-03-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Trace::Helpers::Snapshot`: cognitive state persistence with MessagePack serialization and SHA-512/Ed25519 signing
|
|
7
|
+
- Snapshot save, restore, list, and prune operations with auto-prune on save
|
|
8
|
+
- GAIA lifecycle hooks: auto-save on `service.shutting_down`, auto-restore on `gaia.started`
|
|
9
|
+
- `msgpack` gem dependency
|
|
10
|
+
|
|
11
|
+
## [0.1.1] - 2026-03-18
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Enforce NODE_TYPES validation in SemanticPriming::PrimingNetwork#add_node (returns nil for invalid types)
|
|
4
15
|
|
|
5
16
|
## [0.1.0] - 2026-03-18
|
|
6
17
|
|
data/README.md
CHANGED
|
@@ -1,13 +1,58 @@
|
|
|
1
1
|
# lex-agentic-memory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Domain consolidation gem for memory storage, retrieval, and consolidation. Bundles 18 source extensions into one loadable unit under `Legion::Extensions::Agentic::Memory`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Gem**: `lex-agentic-memory`
|
|
8
|
+
**Version**: 0.1.1
|
|
9
|
+
**Namespace**: `Legion::Extensions::Agentic::Memory`
|
|
10
|
+
|
|
11
|
+
## Sub-Modules
|
|
12
|
+
|
|
13
|
+
| Sub-Module | Source Gem | Purpose |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `Memory::Trace` | `lex-memory` | Memory trace storage, power-law decay, Hebbian association, tiered retrieval |
|
|
16
|
+
| `Memory::Episodic` | `lex-episodic-buffer` | Baddeley & Hitch episodic buffer — integrates working memory channels |
|
|
17
|
+
| `Memory::Semantic` | `lex-semantic-memory` | Long-term conceptual knowledge — spreading activation |
|
|
18
|
+
| `Memory::SemanticPriming` | `lex-semantic-priming` | Prior exposure boosts retrieval speed for related concepts |
|
|
19
|
+
| `Memory::SemanticSatiation` | `lex-semantic-satiation` | Repeated activation reduces salience — cognitive desensitization |
|
|
20
|
+
| `Memory::SourceMonitoring` | `lex-source-monitoring` | Attribution of memories to origin source |
|
|
21
|
+
| `Memory::Transfer` | `lex-transfer-learning` | Knowledge transfer between domains |
|
|
22
|
+
| `Memory::Archaeology` | `lex-cognitive-archaeology` | Excavates dormant or deeply buried traces |
|
|
23
|
+
| `Memory::Paleontology` | `lex-cognitive-paleontology` | Excavating old knowledge layers |
|
|
24
|
+
| `Memory::Palimpsest` | `lex-cognitive-palimpsest` | Layered memory overwriting — recovering original layers |
|
|
25
|
+
| `Memory::Compression` | `lex-cognitive-compression` | Memory compression for storage efficiency |
|
|
26
|
+
| `Memory::Hologram` | `lex-cognitive-hologram` | Distributed memory storage with holographic properties |
|
|
27
|
+
| `Memory::Offloading` | `lex-cognitive-offloading` | Externalizing memory to reduce cognitive load |
|
|
28
|
+
| `Memory::Nostalgia` | `lex-cognitive-nostalgia` | Nostalgic retrieval bias — past warmth enhancement |
|
|
29
|
+
| `Memory::Echo` | `lex-cognitive-echo` | Echo/resonance of past experiences |
|
|
30
|
+
| `Memory::EchoChamber` | `lex-cognitive-echo-chamber` | Self-reinforcing memory patterns |
|
|
31
|
+
| `Memory::ImmuneMemory` | `lex-cognitive-immune-memory` | Immune-style memory for threat patterns |
|
|
32
|
+
| `Memory::Reserve` | `lex-cognitive-reserve` | Cognitive reserve capacity |
|
|
33
|
+
|
|
34
|
+
## Actors
|
|
35
|
+
|
|
36
|
+
- `Memory::Episodic::Actors::Decay` — interval actor, decays episodic buffer entries
|
|
37
|
+
- `Memory::Semantic::Actors::Decay` — interval actor, decays semantic memory activation
|
|
38
|
+
- `Memory::SourceMonitoring::Actors::Decay` — interval actor, decays source monitoring confidence
|
|
39
|
+
- `Memory::Trace::Actors::Decay` — runs every 60s, executes `decay_cycle`
|
|
40
|
+
- `Memory::Trace::Actors::TierMigration` — runs every 300s, migrates traces between tiers
|
|
8
41
|
|
|
9
42
|
## Installation
|
|
10
43
|
|
|
11
44
|
```ruby
|
|
12
45
|
gem 'lex-agentic-memory'
|
|
13
46
|
```
|
|
47
|
+
|
|
48
|
+
## Development
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
bundle install
|
|
52
|
+
bundle exec rspec # 1795 examples, 0 failures
|
|
53
|
+
bundle exec rubocop # 0 offenses
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT
|
data/lex-agentic-memory.gemspec
CHANGED
|
@@ -24,6 +24,8 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
end
|
|
25
25
|
spec.require_paths = ['lib']
|
|
26
26
|
|
|
27
|
+
spec.add_dependency 'msgpack', '~> 1.7'
|
|
28
|
+
|
|
27
29
|
spec.add_development_dependency 'rspec', '~> 3.13'
|
|
28
30
|
spec.add_development_dependency 'rubocop', '~> 1.60'
|
|
29
31
|
spec.add_development_dependency 'rubocop-rspec', '~> 2.26'
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'msgpack'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'securerandom'
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Extensions
|
|
9
|
+
module Agentic
|
|
10
|
+
module Memory
|
|
11
|
+
module Trace
|
|
12
|
+
module Helpers
|
|
13
|
+
module Snapshot
|
|
14
|
+
class << self
|
|
15
|
+
def save_snapshot(agent_id:)
|
|
16
|
+
state = gather_state(agent_id)
|
|
17
|
+
packed = MessagePack.pack(state)
|
|
18
|
+
signed = sign_data(packed, agent_id)
|
|
19
|
+
|
|
20
|
+
dir = snapshot_dir(agent_id)
|
|
21
|
+
FileUtils.mkdir_p(dir)
|
|
22
|
+
filename = "#{Time.now.utc.strftime('%Y%m%d%H%M%S%L')}_#{SecureRandom.hex(4)}.snapshot"
|
|
23
|
+
path = File.join(dir, filename)
|
|
24
|
+
File.binwrite(path, signed)
|
|
25
|
+
|
|
26
|
+
prune_snapshots(agent_id: agent_id)
|
|
27
|
+
{ success: true, path: path, size: signed.bytesize }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def restore_snapshot(agent_id:)
|
|
31
|
+
path = latest_snapshot_path(agent_id)
|
|
32
|
+
return { success: false, reason: :no_snapshot } unless path
|
|
33
|
+
|
|
34
|
+
raw = File.binread(path)
|
|
35
|
+
return { success: false, reason: :too_small } if raw.bytesize < 65
|
|
36
|
+
|
|
37
|
+
signature = raw[-64..]
|
|
38
|
+
packed = raw[0..-65]
|
|
39
|
+
|
|
40
|
+
unless verify_data(packed, signature, agent_id)
|
|
41
|
+
Legion::Logging.warn "[snapshot] signature verification failed for #{agent_id}" if defined?(Legion::Logging)
|
|
42
|
+
return { success: false, reason: :invalid_signature }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
state = MessagePack.unpack(packed, symbolize_keys: true)
|
|
46
|
+
distribute_state(state)
|
|
47
|
+
{ success: true, agent_id: agent_id, timestamp: state[:timestamp] }
|
|
48
|
+
rescue StandardError => e
|
|
49
|
+
Legion::Logging.warn "[snapshot] restore failed: #{e.message}" if defined?(Legion::Logging)
|
|
50
|
+
{ success: false, reason: :error, message: e.message }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def list_snapshots(agent_id:)
|
|
54
|
+
dir = snapshot_dir(agent_id)
|
|
55
|
+
return { success: true, snapshots: [] } unless Dir.exist?(dir)
|
|
56
|
+
|
|
57
|
+
files = Dir.glob(File.join(dir, '*.snapshot')).map do |f|
|
|
58
|
+
{ filename: File.basename(f), size: File.size(f), mtime: File.mtime(f) }
|
|
59
|
+
end
|
|
60
|
+
{ success: true, snapshots: files }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def prune_snapshots(agent_id:, max_count: 10)
|
|
64
|
+
dir = snapshot_dir(agent_id)
|
|
65
|
+
return { success: true, pruned: 0 } unless Dir.exist?(dir)
|
|
66
|
+
|
|
67
|
+
files = Dir.glob(File.join(dir, '*.snapshot'))
|
|
68
|
+
excess = files.size - max_count
|
|
69
|
+
return { success: true, pruned: 0 } if excess <= 0
|
|
70
|
+
|
|
71
|
+
files.first(excess).each { |f| File.delete(f) }
|
|
72
|
+
{ success: true, pruned: excess }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def snapshot_dir(agent_id)
|
|
78
|
+
base = Legion::Settings.dig(:snapshot, :directory) if defined?(Legion::Settings)
|
|
79
|
+
File.join(base || File.expand_path('~/.legionio/snapshots'), agent_id.to_s)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def latest_snapshot_path(agent_id)
|
|
83
|
+
dir = snapshot_dir(agent_id)
|
|
84
|
+
return nil unless Dir.exist?(dir)
|
|
85
|
+
|
|
86
|
+
Dir.glob(File.join(dir, '*.snapshot')).max
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def gather_state(agent_id)
|
|
90
|
+
state = { agent_id: agent_id, schema_version: 1, timestamp: Time.now.utc.iso8601 }
|
|
91
|
+
|
|
92
|
+
store = Legion::Extensions::Agentic::Memory::Trace.shared_store
|
|
93
|
+
state[:memory_traces] = if store.respond_to?(:all_traces)
|
|
94
|
+
traces = store.all_traces
|
|
95
|
+
traces.is_a?(Array) ? traces : traces.values
|
|
96
|
+
else
|
|
97
|
+
[]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
state[:personality_state] = {}
|
|
101
|
+
state[:mood_state] = {}
|
|
102
|
+
state[:trust_scores] = {}
|
|
103
|
+
state[:reflection_history] = []
|
|
104
|
+
state
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def distribute_state(state)
|
|
108
|
+
return unless state[:memory_traces]
|
|
109
|
+
|
|
110
|
+
store = Legion::Extensions::Agentic::Memory::Trace.shared_store
|
|
111
|
+
if store.respond_to?(:restore_traces)
|
|
112
|
+
store.restore_traces(state[:memory_traces])
|
|
113
|
+
elsif store.respond_to?(:store)
|
|
114
|
+
state[:memory_traces].each { |t| store.store(t) }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def sign_data(data, _agent_id)
|
|
119
|
+
if defined?(Legion::Crypt) && Legion::Crypt.respond_to?(:ed25519_sign)
|
|
120
|
+
signature = Legion::Crypt.ed25519_sign(data)
|
|
121
|
+
data + signature
|
|
122
|
+
else
|
|
123
|
+
require 'digest'
|
|
124
|
+
hash = Digest::SHA512.digest(data)
|
|
125
|
+
data + hash[0, 64]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def verify_data(data, signature, _agent_id)
|
|
130
|
+
if defined?(Legion::Crypt) && Legion::Crypt.respond_to?(:ed25519_verify)
|
|
131
|
+
Legion::Crypt.ed25519_verify(data, signature)
|
|
132
|
+
else
|
|
133
|
+
require 'digest'
|
|
134
|
+
expected = Digest::SHA512.digest(data)[0, 64]
|
|
135
|
+
signature == expected
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -33,3 +33,45 @@ module Legion
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
# Snapshot lifecycle hooks
|
|
38
|
+
if defined?(Legion::Events)
|
|
39
|
+
snapshot_enabled = begin
|
|
40
|
+
Legion::Settings.dig(:snapshot, :enabled)
|
|
41
|
+
rescue StandardError
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
if snapshot_enabled
|
|
45
|
+
require 'legion/extensions/agentic/memory/trace/helpers/snapshot'
|
|
46
|
+
|
|
47
|
+
Legion::Events.on('service.shutting_down') do
|
|
48
|
+
next unless begin
|
|
49
|
+
Legion::Settings.dig(:snapshot, :auto_save_on_shutdown)
|
|
50
|
+
rescue StandardError
|
|
51
|
+
true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
agent_id = begin
|
|
55
|
+
Legion::Settings.dig(:agent, :id)
|
|
56
|
+
rescue StandardError
|
|
57
|
+
nil
|
|
58
|
+
end || 'default'
|
|
59
|
+
Legion::Extensions::Agentic::Memory::Trace::Helpers::Snapshot.save_snapshot(agent_id: agent_id)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Legion::Events.once('gaia.started') do
|
|
63
|
+
next unless begin
|
|
64
|
+
Legion::Settings.dig(:snapshot, :auto_restore_on_boot)
|
|
65
|
+
rescue StandardError
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
agent_id = begin
|
|
70
|
+
Legion::Settings.dig(:agent, :id)
|
|
71
|
+
rescue StandardError
|
|
72
|
+
nil
|
|
73
|
+
end || 'default'
|
|
74
|
+
Legion::Extensions::Agentic::Memory::Trace::Helpers::Snapshot.restore_snapshot(agent_id: agent_id)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -9,7 +9,7 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Episodic do
|
|
|
9
9
|
expect(Legion::Extensions::Agentic::Memory::Episodic::VERSION).to be_a(String)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
it 'version is
|
|
13
|
-
expect(Legion::Extensions::Agentic::Memory::Episodic::VERSION).to
|
|
12
|
+
it 'version is a semver string' do
|
|
13
|
+
expect(Legion::Extensions::Agentic::Memory::Episodic::VERSION).to match(/\A\d+\.\d+\.\d+\z/)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'GAIA snapshot hooks' do
|
|
6
|
+
it 'entry point has snapshot lifecycle hooks block' do
|
|
7
|
+
entry_point = File.read(
|
|
8
|
+
File.expand_path('../../../../../lib/legion/extensions/agentic/memory.rb', __dir__)
|
|
9
|
+
)
|
|
10
|
+
expect(entry_point).to include('service.shutting_down')
|
|
11
|
+
expect(entry_point).to include('gaia.started')
|
|
12
|
+
expect(entry_point).to include('Trace::Helpers::Snapshot')
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.describe Legion::Extensions::Agentic::Memory::ImmuneMemory do
|
|
4
4
|
it 'has a version number' do
|
|
5
|
-
expect(Legion::Extensions::Agentic::Memory::ImmuneMemory::VERSION).
|
|
5
|
+
expect(Legion::Extensions::Agentic::Memory::ImmuneMemory::VERSION).not_to be_nil
|
|
6
6
|
end
|
|
7
7
|
end
|
|
@@ -18,6 +18,18 @@ RSpec.describe Legion::Extensions::Agentic::Memory::SemanticPriming::Helpers::Pr
|
|
|
18
18
|
found = network.find_node_by_label(label: 'stored')
|
|
19
19
|
expect(found.id).to eq(node.id)
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
it 'rejects invalid node_type' do
|
|
23
|
+
expect(network.add_node(label: 'bad', node_type: :kinesthetic)).to be_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'accepts all valid NODE_TYPES' do
|
|
27
|
+
constants = Legion::Extensions::Agentic::Memory::SemanticPriming::Helpers::Constants
|
|
28
|
+
constants::NODE_TYPES.each do |nt|
|
|
29
|
+
node = network.add_node(label: "node_#{nt}", node_type: nt)
|
|
30
|
+
expect(node).not_to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
21
33
|
end
|
|
22
34
|
|
|
23
35
|
describe '#remove_node' do
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.describe Legion::Extensions::Agentic::Memory::SemanticPriming do
|
|
4
4
|
it 'has a version number' do
|
|
5
|
-
expect(Legion::Extensions::Agentic::Memory::SemanticPriming::VERSION).
|
|
5
|
+
expect(Legion::Extensions::Agentic::Memory::SemanticPriming::VERSION).not_to be_nil
|
|
6
6
|
end
|
|
7
7
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'legion/extensions/agentic/memory/trace/helpers/snapshot'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
require 'msgpack'
|
|
7
|
+
|
|
8
|
+
RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Helpers::Snapshot do
|
|
9
|
+
let(:tmpdir) { Dir.mktmpdir('legion-snapshot-test') }
|
|
10
|
+
let(:agent_id) { 'test-agent' }
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
allow(described_class).to receive(:snapshot_dir) do |aid|
|
|
14
|
+
File.join(tmpdir, aid.to_s)
|
|
15
|
+
end
|
|
16
|
+
Legion::Extensions::Agentic::Memory::Trace.reset_store!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
after do
|
|
20
|
+
FileUtils.rm_rf(tmpdir)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '.save_snapshot' do
|
|
24
|
+
it 'creates a snapshot file' do
|
|
25
|
+
result = described_class.save_snapshot(agent_id: agent_id)
|
|
26
|
+
expect(result[:success]).to be true
|
|
27
|
+
expect(result[:path]).to end_with('.snapshot')
|
|
28
|
+
expect(File.exist?(result[:path])).to be true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'creates a non-empty file' do
|
|
32
|
+
result = described_class.save_snapshot(agent_id: agent_id)
|
|
33
|
+
expect(File.size(result[:path])).to be > 64
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '.restore_snapshot' do
|
|
38
|
+
it 'restores from latest snapshot' do
|
|
39
|
+
described_class.save_snapshot(agent_id: agent_id)
|
|
40
|
+
result = described_class.restore_snapshot(agent_id: agent_id)
|
|
41
|
+
expect(result[:success]).to be true
|
|
42
|
+
expect(result[:agent_id]).to eq(agent_id)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'returns no_snapshot when none exists' do
|
|
46
|
+
result = described_class.restore_snapshot(agent_id: 'nonexistent')
|
|
47
|
+
expect(result[:success]).to be false
|
|
48
|
+
expect(result[:reason]).to eq(:no_snapshot)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'detects tampered snapshot' do
|
|
52
|
+
save_result = described_class.save_snapshot(agent_id: agent_id)
|
|
53
|
+
data = File.binread(save_result[:path])
|
|
54
|
+
data[0] = (data[0].ord ^ 0xFF).chr
|
|
55
|
+
File.binwrite(save_result[:path], data)
|
|
56
|
+
|
|
57
|
+
result = described_class.restore_snapshot(agent_id: agent_id)
|
|
58
|
+
expect(result[:success]).to be false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe '.list_snapshots' do
|
|
63
|
+
it 'lists saved snapshots' do
|
|
64
|
+
described_class.save_snapshot(agent_id: agent_id)
|
|
65
|
+
described_class.save_snapshot(agent_id: agent_id)
|
|
66
|
+
result = described_class.list_snapshots(agent_id: agent_id)
|
|
67
|
+
expect(result[:success]).to be true
|
|
68
|
+
expect(result[:snapshots].size).to eq(2)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'returns empty list when no snapshots exist' do
|
|
72
|
+
result = described_class.list_snapshots(agent_id: 'no-such-agent')
|
|
73
|
+
expect(result[:snapshots]).to be_empty
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '.prune_snapshots' do
|
|
78
|
+
it 'removes excess snapshots keeping newest' do
|
|
79
|
+
15.times { described_class.save_snapshot(agent_id: agent_id) }
|
|
80
|
+
result = described_class.prune_snapshots(agent_id: agent_id, max_count: 5)
|
|
81
|
+
expect(result[:pruned]).to eq(5)
|
|
82
|
+
|
|
83
|
+
list = described_class.list_snapshots(agent_id: agent_id)
|
|
84
|
+
expect(list[:snapshots].size).to eq(5)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-agentic-memory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: msgpack
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.7'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.7'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: rspec
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -198,6 +212,7 @@ files:
|
|
|
198
212
|
- lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb
|
|
199
213
|
- lib/legion/extensions/agentic/memory/trace/helpers/decay.rb
|
|
200
214
|
- lib/legion/extensions/agentic/memory/trace/helpers/error_tracer.rb
|
|
215
|
+
- lib/legion/extensions/agentic/memory/trace/helpers/snapshot.rb
|
|
201
216
|
- lib/legion/extensions/agentic/memory/trace/helpers/store.rb
|
|
202
217
|
- lib/legion/extensions/agentic/memory/trace/helpers/trace.rb
|
|
203
218
|
- lib/legion/extensions/agentic/memory/trace/local_migrations/20260316000001_create_memory_traces.rb
|
|
@@ -244,6 +259,7 @@ files:
|
|
|
244
259
|
- spec/legion/extensions/agentic/memory/episodic/helpers/episodic_binding_spec.rb
|
|
245
260
|
- spec/legion/extensions/agentic/memory/episodic/helpers/episodic_store_spec.rb
|
|
246
261
|
- spec/legion/extensions/agentic/memory/episodic/runners/episodic_buffer_spec.rb
|
|
262
|
+
- spec/legion/extensions/agentic/memory/gaia_hooks_spec.rb
|
|
247
263
|
- spec/legion/extensions/agentic/memory/hologram/client_spec.rb
|
|
248
264
|
- spec/legion/extensions/agentic/memory/hologram/cognitive_hologram_spec.rb
|
|
249
265
|
- spec/legion/extensions/agentic/memory/hologram/helpers/constants_spec.rb
|
|
@@ -309,6 +325,7 @@ files:
|
|
|
309
325
|
- spec/legion/extensions/agentic/memory/trace/batch_decay_spec.rb
|
|
310
326
|
- spec/legion/extensions/agentic/memory/trace/client_spec.rb
|
|
311
327
|
- spec/legion/extensions/agentic/memory/trace/helpers/decay_spec.rb
|
|
328
|
+
- spec/legion/extensions/agentic/memory/trace/helpers/snapshot_spec.rb
|
|
312
329
|
- spec/legion/extensions/agentic/memory/trace/helpers/store_spec.rb
|
|
313
330
|
- spec/legion/extensions/agentic/memory/trace/helpers/trace_spec.rb
|
|
314
331
|
- spec/legion/extensions/agentic/memory/trace/local_persistence_spec.rb
|