swarm_memory 2.2.3 → 2.2.4

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: 6217058c4241029650e057e4f28c75eb1c6105f797657eb7c039eb307fe9bcab
4
- data.tar.gz: a9f5d039fe4dd776dff184fce3a539bf40e3bfe9f150698b26847e2953bc5e46
3
+ metadata.gz: 768a8a8cd1d0ab5a3edff5e6e0c54e3fdce1e6c6af281d6a39285019167b87c8
4
+ data.tar.gz: aa9e396d3c72e53bf49459828c635148205c523e6d16bb42e7f6e4e5856a1d4c
5
5
  SHA512:
6
- metadata.gz: 883afdf0f09de8425226e1ef1138b9f657de2a92b9efbb2b2262315479c3bc2a83542151a73d484ee632d6e5e5921e1f2232d7361d6c55457d530d982569e681
7
- data.tar.gz: 963e4ba618cde5bdeb496815044b9c791fb68c9fb28f7543fcba75d93f77d095638d05417338132143b57dc0c6b845b7fad4f8853b433b845545272c36aa2e37
6
+ metadata.gz: c35aad639f910180b0bcd73db10b8db18f4cb9bde3d136789e77b26ac1a1a2a66fc476b1cce9731bf06566ad8bf9bfbc8edfe0c513b62a303c79346c6efb5b52
7
+ data.tar.gz: 18f0c1c5fc97d2946174e43d61c86493cbaa31626a8c6ecbf019ad12ca9654ebdeb77475305a79fb1c11ed85eb85b35be44fad349bb56806e039ea6afafea247
@@ -138,7 +138,7 @@ module SwarmMemory
138
138
  result << "Memory entries matching '#{pattern}' (#{entries.size} #{entries.size == 1 ? "entry" : "entries"}):"
139
139
 
140
140
  entries.each do |entry|
141
- result << " memory://#{entry[:path]} - \"#{entry[:title]}\" (#{format_bytes(entry[:size])})"
141
+ result << "- memory://#{entry[:path]} \"#{entry[:title]}\" (#{format_bytes(entry[:size])})"
142
142
  end
143
143
 
144
144
  output = result.join("\n")
@@ -7,6 +7,8 @@ module SwarmMemory
7
7
  # Searches content stored in memory entries using regex patterns.
8
8
  # Each agent has its own isolated memory storage.
9
9
  class MemoryGrep < RubyLLM::Tool
10
+ include TitleLookup
11
+
10
12
  description <<~DESC
11
13
  Search your memory content using regular expression patterns (like grep).
12
14
 
@@ -197,7 +199,7 @@ module SwarmMemory
197
199
  result = []
198
200
  result << "Memory entries matching #{search_desc} (#{paths.size} #{paths.size == 1 ? "entry" : "entries"}):"
199
201
  paths.each do |path|
200
- result << " memory://#{path}"
202
+ result << "- #{format_memory_path_with_title(path)}"
201
203
  end
202
204
  result.join("\n")
203
205
  end
@@ -7,8 +7,10 @@ module SwarmMemory
7
7
  # Retrieves content stored by this agent using memory_write.
8
8
  # Each agent has its own isolated memory storage.
9
9
  class MemoryRead < RubyLLM::Tool
10
+ include TitleLookup
11
+
10
12
  description <<~DESC
11
- Read content from your memory storage and retrieve all associated metadata.
13
+ Read content from your memory storage.
12
14
 
13
15
  REQUIRED: Provide the file_path parameter - the path to the memory entry you want to read.
14
16
 
@@ -25,9 +27,8 @@ module SwarmMemory
25
27
  INVALID: documentation/, reference/, tutorial/, parallel/, analysis/, notes/
26
28
 
27
29
  **Returns:**
28
- JSON with two fields:
29
- - content: Markdown content with line numbers (same format as Read tool)
30
- - metadata: All metadata (title, type, tags, tools, permissions, confidence, etc.)
30
+ Markdown content with line numbers (same format as 'cat -n').
31
+ If the entry has related memories, a system-reminder section is appended listing them.
31
32
 
32
33
  **Examples:**
33
34
  - MemoryRead(file_path: "concept/ruby/classes.md") - Read a concept
@@ -38,6 +39,7 @@ module SwarmMemory
38
39
  - Always read entries before editing them with MemoryEdit
39
40
  - Line numbers in output are for reference only - don't include them when editing
40
41
  - Each read is tracked to enforce read-before-edit patterns
42
+ - Related memories in the system-reminder can be read with MemoryRead for additional context
41
43
  DESC
42
44
 
43
45
  param :file_path,
@@ -62,7 +64,7 @@ module SwarmMemory
62
64
  # Execute the tool
63
65
  #
64
66
  # @param file_path [String] Path to read from
65
- # @return [String] JSON with content and metadata
67
+ # @return [String] Content with line numbers and optional related memories reminder
66
68
  def execute(file_path:)
67
69
  # Read full entry with metadata
68
70
  entry = @storage.read_entry(file_path: file_path)
@@ -70,8 +72,14 @@ module SwarmMemory
70
72
  # Register this read in the tracker with content digest
71
73
  Core::StorageReadTracker.register_read(@agent_name, file_path, entry.content)
72
74
 
73
- # Always return JSON format (metadata always exists - at minimum title)
74
- format_as_json(entry)
75
+ # Return plain text with line numbers
76
+ result = format_with_line_numbers(entry.content)
77
+
78
+ # Append related memories reminder if present
79
+ related_paths = entry.metadata&.dig("related") || []
80
+ result += format_related_memories_reminder(related_paths) if related_paths.any?
81
+
82
+ result
75
83
  rescue ArgumentError => e
76
84
  validation_error(e.message)
77
85
  end
@@ -82,29 +90,6 @@ module SwarmMemory
82
90
  "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
83
91
  end
84
92
 
85
- # Format entry as JSON with content and metadata
86
- #
87
- # Returns a clean JSON format separating content from metadata.
88
- # This prevents agents from mimicking metadata format when writing.
89
- #
90
- # Content includes line numbers (same format as Read tool).
91
- # Metadata always includes at least title (from Entry).
92
- # Additional metadata comes from the metadata hash (type, tags, tools, etc.)
93
- #
94
- # @param entry [Core::Entry] Entry with content and metadata
95
- # @return [String] Pretty-printed JSON
96
- def format_as_json(entry)
97
- # Build metadata hash with title included
98
- metadata_hash = { "title" => entry.title }
99
- metadata_hash.merge!(entry.metadata) if entry.metadata
100
-
101
- result = {
102
- content: format_with_line_numbers(entry.content),
103
- metadata: metadata_hash,
104
- }
105
- JSON.pretty_generate(result)
106
- end
107
-
108
93
  # Format content with line numbers (same format as Read tool)
109
94
  #
110
95
  # @param content [String] Content to format
@@ -114,10 +99,29 @@ module SwarmMemory
114
99
  output_lines = lines.each_with_index.map do |line, idx|
115
100
  line_number = idx + 1
116
101
  display_line = line.chomp
117
- "#{line_number.to_s.rjust(6)}→#{display_line}"
102
+ "#{line_number.to_s.rjust(6)} #{display_line}"
118
103
  end
119
104
  output_lines.join("\n")
120
105
  end
106
+
107
+ # Format related memories as a system-reminder section
108
+ #
109
+ # Looks up titles for each related memory path and formats
110
+ # them as a system reminder to help agents discover related content.
111
+ #
112
+ # @param related_paths [Array<String>] Array of memory paths (with or without memory:// prefix)
113
+ # @return [String] Formatted system-reminder section
114
+ def format_related_memories_reminder(related_paths)
115
+ lines = ["\n\n<system-reminder>"]
116
+ lines << "Related memories that may provide additional context:"
117
+
118
+ related_paths.each do |path|
119
+ lines << "- #{format_memory_path_with_title(path)}"
120
+ end
121
+
122
+ lines << "</system-reminder>"
123
+ lines.join("\n")
124
+ end
121
125
  end
122
126
  end
123
127
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmMemory
4
+ module Tools
5
+ # Shared module for looking up memory entry titles
6
+ #
7
+ # Provides a consistent way to look up titles for memory entries
8
+ # across different tools (MemoryRead, MemoryGrep, etc.)
9
+ #
10
+ # @example Including in a tool
11
+ # class MemoryGrep < RubyLLM::Tool
12
+ # include TitleLookup
13
+ #
14
+ # def some_method
15
+ # title = lookup_title("concept/ruby/classes.md")
16
+ # end
17
+ # end
18
+ module TitleLookup
19
+ # Look up the title of a memory entry
20
+ #
21
+ # @param path [String] Path to the memory entry
22
+ # @return [String, nil] Title if found, nil otherwise
23
+ #
24
+ # @example
25
+ # title = lookup_title("concept/ruby/classes.md")
26
+ # # => "Ruby Classes"
27
+ def lookup_title(path)
28
+ entry = @storage.read_entry(file_path: path)
29
+ entry.title
30
+ rescue StandardError
31
+ nil
32
+ end
33
+
34
+ # Format a memory path with its title
35
+ #
36
+ # Normalizes the path (removes memory:// prefix if present) and
37
+ # formats it with the title in quotes if available.
38
+ #
39
+ # @param path [String] Path to the memory entry (with or without memory:// prefix)
40
+ # @return [String] Formatted string like 'memory://path "Title"' or 'memory://path'
41
+ #
42
+ # @example With title found
43
+ # format_memory_path_with_title("concept/ruby/classes.md")
44
+ # # => 'memory://concept/ruby/classes.md "Ruby Classes"'
45
+ #
46
+ # @example With memory:// prefix
47
+ # format_memory_path_with_title("memory://concept/ruby/classes.md")
48
+ # # => 'memory://concept/ruby/classes.md "Ruby Classes"'
49
+ #
50
+ # @example When title not found
51
+ # format_memory_path_with_title("nonexistent.md")
52
+ # # => 'memory://nonexistent.md'
53
+ def format_memory_path_with_title(path)
54
+ normalized_path = path.sub(%r{^memory://}, "")
55
+ title = lookup_title(normalized_path)
56
+
57
+ if title
58
+ "memory://#{normalized_path} \"#{title}\""
59
+ else
60
+ "memory://#{normalized_path}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmMemory
4
- VERSION = "2.2.3"
4
+ VERSION = "2.2.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swarm_memory
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 2.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -71,14 +71,14 @@ dependencies:
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 2.5.1
74
+ version: 2.5.2
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 2.5.1
81
+ version: 2.5.2
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: zeitwerk
84
84
  requirement: !ruby/object:Gem::Requirement
@@ -140,14 +140,15 @@ files:
140
140
  - lib/swarm_memory/tools/memory_grep.rb
141
141
  - lib/swarm_memory/tools/memory_read.rb
142
142
  - lib/swarm_memory/tools/memory_write.rb
143
+ - lib/swarm_memory/tools/title_lookup.rb
143
144
  - lib/swarm_memory/utils.rb
144
145
  - lib/swarm_memory/version.rb
145
- homepage: https://github.com/parruda/claude-swarm
146
+ homepage: https://github.com/parruda/swarm
146
147
  licenses:
147
148
  - MIT
148
149
  metadata:
149
- source_code_uri: https://github.com/parruda/claude-swarm
150
- changelog_uri: https://github.com/parruda/claude-swarm/blob/main/docs/v2/CHANGELOG.swarm_memory.md
150
+ source_code_uri: https://github.com/parruda/swarm
151
+ changelog_uri: https://github.com/parruda/swarm/blob/main/docs/v2/CHANGELOG.swarm_memory.md
151
152
  rdoc_options: []
152
153
  require_paths:
153
154
  - lib