swarm_memory 2.1.4 → 2.1.6

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.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. data/lib/swarm_memory.rb +7 -2
  4. metadata +6 -185
  5. data/lib/claude_swarm/base_executor.rb +0 -133
  6. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  7. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  8. data/lib/claude_swarm/cli.rb +0 -697
  9. data/lib/claude_swarm/commands/ps.rb +0 -215
  10. data/lib/claude_swarm/commands/show.rb +0 -139
  11. data/lib/claude_swarm/configuration.rb +0 -373
  12. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  13. data/lib/claude_swarm/json_handler.rb +0 -91
  14. data/lib/claude_swarm/mcp_generator.rb +0 -243
  15. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  16. data/lib/claude_swarm/openai/executor.rb +0 -256
  17. data/lib/claude_swarm/openai/responses.rb +0 -319
  18. data/lib/claude_swarm/orchestrator.rb +0 -878
  19. data/lib/claude_swarm/process_tracker.rb +0 -78
  20. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  21. data/lib/claude_swarm/session_path.rb +0 -42
  22. data/lib/claude_swarm/settings_generator.rb +0 -77
  23. data/lib/claude_swarm/system_utils.rb +0 -46
  24. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  25. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  27. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  28. data/lib/claude_swarm/version.rb +0 -5
  29. data/lib/claude_swarm/worktree_manager.rb +0 -475
  30. data/lib/claude_swarm/yaml_loader.rb +0 -22
  31. data/lib/claude_swarm.rb +0 -67
  32. data/lib/swarm_cli/cli.rb +0 -201
  33. data/lib/swarm_cli/command_registry.rb +0 -61
  34. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  35. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  36. data/lib/swarm_cli/commands/migrate.rb +0 -55
  37. data/lib/swarm_cli/commands/run.rb +0 -173
  38. data/lib/swarm_cli/config_loader.rb +0 -98
  39. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  40. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  41. data/lib/swarm_cli/interactive_repl.rb +0 -924
  42. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  43. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  44. data/lib/swarm_cli/migrate_options.rb +0 -54
  45. data/lib/swarm_cli/migrator.rb +0 -132
  46. data/lib/swarm_cli/options.rb +0 -151
  47. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  48. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  49. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  50. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  51. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  52. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  53. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  54. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  55. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  56. data/lib/swarm_cli/ui/icons.rb +0 -36
  57. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  58. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  59. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  60. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  61. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  62. data/lib/swarm_cli/version.rb +0 -5
  63. data/lib/swarm_cli.rb +0 -46
  64. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  65. data/lib/swarm_sdk/agent/builder.rb +0 -552
  66. data/lib/swarm_sdk/agent/chat.rb +0 -774
  67. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  68. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  69. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  70. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  71. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  72. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  73. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  75. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  76. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  77. data/lib/swarm_sdk/agent/context.rb +0 -116
  78. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  79. data/lib/swarm_sdk/agent/definition.rb +0 -477
  80. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  81. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  82. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  83. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  84. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  85. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  86. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  87. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  88. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  89. data/lib/swarm_sdk/configuration.rb +0 -135
  90. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  91. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  92. data/lib/swarm_sdk/context_compactor.rb +0 -335
  93. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  94. data/lib/swarm_sdk/context_management/context.rb +0 -328
  95. data/lib/swarm_sdk/defaults.rb +0 -196
  96. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  97. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  98. data/lib/swarm_sdk/hooks/context.rb +0 -197
  99. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  100. data/lib/swarm_sdk/hooks/error.rb +0 -29
  101. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  102. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  103. data/lib/swarm_sdk/hooks/result.rb +0 -150
  104. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  105. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  106. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  107. data/lib/swarm_sdk/log_collector.rb +0 -227
  108. data/lib/swarm_sdk/log_stream.rb +0 -127
  109. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  110. data/lib/swarm_sdk/model_aliases.json +0 -8
  111. data/lib/swarm_sdk/models.json +0 -1
  112. data/lib/swarm_sdk/models.rb +0 -120
  113. data/lib/swarm_sdk/node_context.rb +0 -245
  114. data/lib/swarm_sdk/observer/builder.rb +0 -81
  115. data/lib/swarm_sdk/observer/config.rb +0 -45
  116. data/lib/swarm_sdk/observer/manager.rb +0 -236
  117. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  118. data/lib/swarm_sdk/permissions/config.rb +0 -239
  119. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  120. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  121. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  122. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  123. data/lib/swarm_sdk/plugin.rb +0 -309
  124. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  125. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  126. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  127. data/lib/swarm_sdk/restore_result.rb +0 -65
  128. data/lib/swarm_sdk/result.rb +0 -123
  129. data/lib/swarm_sdk/snapshot.rb +0 -156
  130. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  131. data/lib/swarm_sdk/state_restorer.rb +0 -476
  132. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  133. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  134. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  135. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  136. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  137. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  138. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  139. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  140. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  141. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  142. data/lib/swarm_sdk/swarm.rb +0 -717
  143. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  144. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  145. data/lib/swarm_sdk/tools/bash.rb +0 -282
  146. data/lib/swarm_sdk/tools/clock.rb +0 -44
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  160. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  161. data/lib/swarm_sdk/tools/read.rb +0 -261
  162. data/lib/swarm_sdk/tools/registry.rb +0 -205
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  166. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  167. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  168. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  169. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  170. data/lib/swarm_sdk/tools/think.rb +0 -98
  171. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  172. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  173. data/lib/swarm_sdk/tools/write.rb +0 -112
  174. data/lib/swarm_sdk/utils.rb +0 -68
  175. data/lib/swarm_sdk/validation_result.rb +0 -33
  176. data/lib/swarm_sdk/version.rb +0 -5
  177. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  178. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  179. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  180. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  181. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  182. data/lib/swarm_sdk/workflow.rb +0 -554
  183. data/lib/swarm_sdk.rb +0 -524
  184. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -1,272 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Stores
6
- # ScratchpadStorage provides volatile, shared storage
7
- #
8
- # Features:
9
- # - Shared: All agents share the same scratchpad
10
- # - Volatile: NEVER persists - all data lost when process ends
11
- # - Path-based: Hierarchical organization using file-path-like addresses
12
- # - Metadata-rich: Stores content + title + timestamp + size
13
- # - Thread-safe: Mutex-protected operations
14
- #
15
- # Use for temporary, cross-agent communication within a single session.
16
- class ScratchpadStorage < Storage
17
- # Initialize scratchpad storage (always volatile)
18
- #
19
- # @param total_size_limit [Integer, nil] Maximum total size in bytes (defaults to Defaults::Storage::TOTAL_SIZE_BYTES)
20
- def initialize(total_size_limit: nil)
21
- super() # Initialize parent Storage class
22
- @entries = {}
23
- @total_size = 0
24
- @total_size_limit = total_size_limit || Defaults::Storage::TOTAL_SIZE_BYTES
25
- @mutex = Mutex.new
26
- end
27
-
28
- # Write content to scratchpad
29
- #
30
- # @param file_path [String] Path to store content
31
- # @param content [String] Content to store
32
- # @param title [String] Brief title describing the content
33
- # @raise [ArgumentError] If size limits are exceeded
34
- # @return [Entry] The created entry
35
- def write(file_path:, content:, title:)
36
- @mutex.synchronize do
37
- raise ArgumentError, "file_path is required" if file_path.nil? || file_path.to_s.strip.empty?
38
- raise ArgumentError, "content is required" if content.nil?
39
- raise ArgumentError, "title is required" if title.nil? || title.to_s.strip.empty?
40
-
41
- content_size = content.bytesize
42
-
43
- # Check entry size limit
44
- if content_size > Defaults::Storage::ENTRY_SIZE_BYTES
45
- raise ArgumentError, "Content exceeds maximum size (#{format_bytes(Defaults::Storage::ENTRY_SIZE_BYTES)}). " \
46
- "Current: #{format_bytes(content_size)}"
47
- end
48
-
49
- # Calculate new total size
50
- existing_entry = @entries[file_path]
51
- existing_size = existing_entry ? existing_entry.size : 0
52
- new_total_size = @total_size - existing_size + content_size
53
-
54
- # Check total size limit
55
- if new_total_size > @total_size_limit
56
- raise ArgumentError, "Scratchpad full (#{format_bytes(@total_size_limit)} limit). " \
57
- "Current: #{format_bytes(@total_size)}, " \
58
- "Would be: #{format_bytes(new_total_size)}. " \
59
- "Clear old entries or use smaller content."
60
- end
61
-
62
- # Create entry
63
- entry = Entry.new(
64
- content: content,
65
- title: title,
66
- updated_at: Time.now,
67
- size: content_size,
68
- )
69
-
70
- # Update storage
71
- @entries[file_path] = entry
72
- @total_size = new_total_size
73
-
74
- entry
75
- end
76
- end
77
-
78
- # Read content from scratchpad
79
- #
80
- # @param file_path [String] Path to read from
81
- # @raise [ArgumentError] If path not found
82
- # @return [String] Content at the path
83
- def read(file_path:)
84
- raise ArgumentError, "file_path is required" if file_path.nil? || file_path.to_s.strip.empty?
85
-
86
- entry = @entries[file_path]
87
- raise ArgumentError, "scratchpad://#{file_path} not found" unless entry
88
-
89
- entry.content
90
- end
91
-
92
- # Delete a specific entry
93
- #
94
- # @param file_path [String] Path to delete
95
- # @raise [ArgumentError] If path not found
96
- # @return [void]
97
- def delete(file_path:)
98
- @mutex.synchronize do
99
- raise ArgumentError, "file_path is required" if file_path.nil? || file_path.to_s.strip.empty?
100
-
101
- entry = @entries[file_path]
102
- raise ArgumentError, "scratchpad://#{file_path} not found" unless entry
103
-
104
- # Update total size
105
- @total_size -= entry.size
106
-
107
- # Remove entry
108
- @entries.delete(file_path)
109
- end
110
- end
111
-
112
- # List scratchpad entries, optionally filtered by prefix
113
- #
114
- # @param prefix [String, nil] Filter by path prefix
115
- # @return [Array<Hash>] Array of entry metadata (path, title, size, updated_at)
116
- def list(prefix: nil)
117
- entries = @entries
118
-
119
- # Filter by prefix if provided
120
- if prefix && !prefix.empty?
121
- entries = entries.select { |path, _| path.start_with?(prefix) }
122
- end
123
-
124
- # Return metadata sorted by path
125
- entries.map do |path, entry|
126
- {
127
- path: path,
128
- title: entry.title,
129
- size: entry.size,
130
- updated_at: entry.updated_at,
131
- }
132
- end.sort_by { |e| e[:path] }
133
- end
134
-
135
- # Search entries by glob pattern
136
- #
137
- # @param pattern [String] Glob pattern (e.g., "**/*.txt", "parallel/*/task_*")
138
- # @return [Array<Hash>] Array of matching entry metadata, sorted by most recent first
139
- def glob(pattern:)
140
- raise ArgumentError, "pattern is required" if pattern.nil? || pattern.to_s.strip.empty?
141
-
142
- # Convert glob pattern to regex
143
- regex = glob_to_regex(pattern)
144
-
145
- # Filter entries by pattern
146
- matching_entries = @entries.select { |path, _| regex.match?(path) }
147
-
148
- # Return metadata sorted by most recent first
149
- matching_entries.map do |path, entry|
150
- {
151
- path: path,
152
- title: entry.title,
153
- size: entry.size,
154
- updated_at: entry.updated_at,
155
- }
156
- end.sort_by { |e| -e[:updated_at].to_f }
157
- end
158
-
159
- # Search entry content by pattern
160
- #
161
- # @param pattern [String] Regular expression pattern to search for
162
- # @param case_insensitive [Boolean] Whether to perform case-insensitive search
163
- # @param output_mode [String] Output mode: "files_with_matches" (default), "content", or "count"
164
- # @return [Array<Hash>, String] Results based on output_mode
165
- def grep(pattern:, case_insensitive: false, output_mode: "files_with_matches")
166
- raise ArgumentError, "pattern is required" if pattern.nil? || pattern.to_s.strip.empty?
167
-
168
- # Create regex from pattern
169
- flags = case_insensitive ? Regexp::IGNORECASE : 0
170
- regex = Regexp.new(pattern, flags)
171
-
172
- case output_mode
173
- when "files_with_matches"
174
- # Return just the paths that match
175
- matching_paths = @entries.select { |_path, entry| regex.match?(entry.content) }
176
- .map { |path, _| path }
177
- .sort
178
- matching_paths
179
- when "content"
180
- # Return paths with matching lines, sorted by most recent first
181
- results = []
182
- @entries.each do |path, entry|
183
- matching_lines = []
184
- entry.content.each_line.with_index(1) do |line, line_num|
185
- matching_lines << { line_number: line_num, content: line.chomp } if regex.match?(line)
186
- end
187
- results << { path: path, matches: matching_lines, updated_at: entry.updated_at } unless matching_lines.empty?
188
- end
189
- results.sort_by { |r| -r[:updated_at].to_f }.map { |r| r.except(:updated_at) }
190
- when "count"
191
- # Return paths with match counts, sorted by most recent first
192
- results = []
193
- @entries.each do |path, entry|
194
- count = entry.content.scan(regex).size
195
- results << { path: path, count: count, updated_at: entry.updated_at } if count > 0
196
- end
197
- results.sort_by { |r| -r[:updated_at].to_f }.map { |r| r.except(:updated_at) }
198
- else
199
- raise ArgumentError, "Invalid output_mode: #{output_mode}. Must be 'files_with_matches', 'content', or 'count'"
200
- end
201
- end
202
-
203
- # Clear all entries
204
- #
205
- # @return [void]
206
- def clear
207
- @mutex.synchronize do
208
- @entries.clear
209
- @total_size = 0
210
- end
211
- end
212
-
213
- # Get current total size
214
- #
215
- # @return [Integer] Total size in bytes
216
- attr_reader :total_size
217
-
218
- # Get number of entries
219
- #
220
- # @return [Integer] Number of entries
221
- def size
222
- @entries.size
223
- end
224
-
225
- # Get all entries with content for snapshot
226
- #
227
- # Thread-safe method that returns a copy of all entries.
228
- # Used by snapshot/restore functionality.
229
- #
230
- # @return [Hash] { path => Entry }
231
- def all_entries
232
- @mutex.synchronize do
233
- @entries.dup
234
- end
235
- end
236
-
237
- # Restore entries from snapshot
238
- #
239
- # Restores entries directly without using write() to preserve timestamps.
240
- # This ensures entry ordering and metadata accuracy after restore.
241
- #
242
- # @param entries_data [Hash] { path => { content:, title:, updated_at:, size: } }
243
- # @return [void]
244
- def restore_entries(entries_data)
245
- @mutex.synchronize do
246
- entries_data.each do |path, data|
247
- # Handle both symbol and string keys from JSON
248
- content = data[:content] || data["content"]
249
- title = data[:title] || data["title"]
250
- updated_at_str = data[:updated_at] || data["updated_at"]
251
-
252
- # Parse timestamp from ISO8601 string
253
- updated_at = Time.parse(updated_at_str)
254
-
255
- # Create entry with preserved timestamp
256
- entry = Entry.new(
257
- content: content,
258
- title: title,
259
- updated_at: updated_at,
260
- size: content.bytesize,
261
- )
262
-
263
- # Update storage
264
- @entries[path] = entry
265
- @total_size += entry.size
266
- end
267
- end
268
- end
269
- end
270
- end
271
- end
272
- end
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Stores
6
- # Abstract base class for hierarchical key-value storage with metadata
7
- #
8
- # Provides session-scoped storage for agents with path-based organization.
9
- # Subclasses implement persistence behavior (volatile vs persistent).
10
- #
11
- # Features:
12
- # - Path-based: Hierarchical organization using file-path-like addresses
13
- # - Metadata-rich: Stores content + title + timestamp + size
14
- # - Search capabilities: Glob patterns and grep-style content search
15
- # - Thread-safe: Mutex-protected operations
16
- class Storage
17
- # Represents a single storage entry with metadata
18
- Entry = Struct.new(:content, :title, :updated_at, :size, keyword_init: true)
19
-
20
- # Initialize storage
21
- #
22
- # Subclasses should call super() in their initialize method.
23
- # This base implementation does nothing - it exists only to satisfy RuboCop.
24
- def initialize
25
- # Base class initialization - subclasses implement their own logic
26
- end
27
-
28
- # Write content to storage
29
- #
30
- # @param file_path [String] Path to store content
31
- # @param content [String] Content to store
32
- # @param title [String] Brief title describing the content
33
- # @raise [ArgumentError] If size limits are exceeded
34
- # @return [Entry] The created entry
35
- def write(file_path:, content:, title:)
36
- raise NotImplementedError, "Subclass must implement #write"
37
- end
38
-
39
- # Read content from storage
40
- #
41
- # @param file_path [String] Path to read from
42
- # @raise [ArgumentError] If path not found
43
- # @return [String] Content at the path
44
- def read(file_path:)
45
- raise NotImplementedError, "Subclass must implement #read"
46
- end
47
-
48
- # Delete a specific entry
49
- #
50
- # @param file_path [String] Path to delete
51
- # @raise [ArgumentError] If path not found
52
- # @return [void]
53
- def delete(file_path:)
54
- raise NotImplementedError, "Subclass must implement #delete"
55
- end
56
-
57
- # List entries, optionally filtered by prefix
58
- #
59
- # @param prefix [String, nil] Filter by path prefix
60
- # @return [Array<Hash>] Array of entry metadata (path, title, size, updated_at)
61
- def list(prefix: nil)
62
- raise NotImplementedError, "Subclass must implement #list"
63
- end
64
-
65
- # Search entries by glob pattern
66
- #
67
- # @param pattern [String] Glob pattern (e.g., "**/*.txt", "parallel/*/task_*")
68
- # @return [Array<Hash>] Array of matching entry metadata, sorted by most recent first
69
- def glob(pattern:)
70
- raise NotImplementedError, "Subclass must implement #glob"
71
- end
72
-
73
- # Search entry content by pattern
74
- #
75
- # @param pattern [String] Regular expression pattern to search for
76
- # @param case_insensitive [Boolean] Whether to perform case-insensitive search
77
- # @param output_mode [String] Output mode: "files_with_matches" (default), "content", or "count"
78
- # @return [Array<Hash>, String] Results based on output_mode
79
- def grep(pattern:, case_insensitive: false, output_mode: "files_with_matches")
80
- raise NotImplementedError, "Subclass must implement #grep"
81
- end
82
-
83
- # Clear all entries
84
- #
85
- # @return [void]
86
- def clear
87
- raise NotImplementedError, "Subclass must implement #clear"
88
- end
89
-
90
- # Get current total size
91
- #
92
- # @return [Integer] Total size in bytes
93
- def total_size
94
- raise NotImplementedError, "Subclass must implement #total_size"
95
- end
96
-
97
- # Get number of entries
98
- #
99
- # @return [Integer] Number of entries
100
- def size
101
- raise NotImplementedError, "Subclass must implement #size"
102
- end
103
-
104
- protected
105
-
106
- # Format bytes to human-readable size
107
- #
108
- # @param bytes [Integer] Number of bytes
109
- # @return [String] Formatted size (e.g., "1.5MB", "500.0KB")
110
- def format_bytes(bytes)
111
- if bytes >= 1_000_000
112
- "#{(bytes.to_f / 1_000_000).round(1)}MB"
113
- elsif bytes >= 1_000
114
- "#{(bytes.to_f / 1_000).round(1)}KB"
115
- else
116
- "#{bytes}B"
117
- end
118
- end
119
-
120
- # Convert glob pattern to regex
121
- #
122
- # @param pattern [String] Glob pattern
123
- # @return [Regexp] Regular expression
124
- def glob_to_regex(pattern)
125
- # Escape special regex characters except glob wildcards
126
- escaped = Regexp.escape(pattern)
127
-
128
- # Convert glob wildcards to regex
129
- # ** matches any number of directories (including zero)
130
- escaped = escaped.gsub('\*\*', ".*")
131
- # * matches anything except directory separator
132
- escaped = escaped.gsub('\*', "[^/]*")
133
- # ? matches single character except directory separator
134
- escaped = escaped.gsub('\?', "[^/]")
135
-
136
- # Anchor to start and end
137
- Regexp.new("\\A#{escaped}\\z")
138
- end
139
- end
140
- end
141
- end
142
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Stores
6
- # TodoManager provides per-agent todo list storage
7
- #
8
- # Each agent maintains its own independent todo list that persists
9
- # throughout the agent's execution session. This allows agents to
10
- # track progress on complex multi-step tasks.
11
- class TodoManager
12
- @storage = {}
13
- @mutex = Mutex.new
14
-
15
- class << self
16
- # Get the current todo list for an agent
17
- #
18
- # @param agent_id [Symbol, String] Unique agent identifier
19
- # @return [Array<Hash>] Array of todo items
20
- def get_todos(agent_id)
21
- @mutex.synchronize do
22
- @storage[agent_id.to_sym] ||= []
23
- end
24
- end
25
-
26
- # Set the todo list for an agent
27
- #
28
- # @param agent_id [Symbol, String] Unique agent identifier
29
- # @param todos [Array<Hash>] Array of todo items
30
- # @return [Array<Hash>] The stored todos
31
- def set_todos(agent_id, todos)
32
- @mutex.synchronize do
33
- @storage[agent_id.to_sym] = todos
34
- end
35
- end
36
-
37
- # Clear all todos for an agent
38
- #
39
- # @param agent_id [Symbol, String] Unique agent identifier
40
- def clear_todos(agent_id)
41
- @mutex.synchronize do
42
- @storage.delete(agent_id.to_sym)
43
- end
44
- end
45
-
46
- # Clear all todos for all agents
47
- def clear_all
48
- @mutex.synchronize do
49
- @storage.clear
50
- end
51
- end
52
-
53
- # Get summary of all agent todo lists
54
- #
55
- # @return [Hash] Map of agent_id => todo count
56
- def summary
57
- @mutex.synchronize do
58
- @storage.transform_values(&:size)
59
- end
60
- end
61
- end
62
- end
63
- end
64
- end
65
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- # Think tool for explicit reasoning and planning
6
- #
7
- # Allows the agent to write down thoughts, plans, strategies, and intermediate
8
- # calculations. These thoughts become part of the conversation context, enabling
9
- # better attention and reasoning through complex problems.
10
- #
11
- # This is inspired by research showing that explicitly articulating reasoning steps
12
- # (chain-of-thought prompting) leads to significantly better outcomes, especially
13
- # for complex tasks requiring multi-step reasoning or arithmetic.
14
- class Think < RubyLLM::Tool
15
- def name
16
- "Think"
17
- end
18
-
19
- description <<~DESC
20
- **IMPORTANT: You SHOULD use this tool frequently throughout your work. Using this tool leads to significantly
21
- better outcomes and more accurate solutions. Make it a habit to think before acting.**
22
-
23
- This tool allows you to write down your thoughts, plans, strategies, and intermediate calculations.
24
- Think of it as your working memory - just as humans think before speaking or acting, you should think before
25
- using other tools or providing responses.
26
-
27
- **STRONGLY RECOMMENDED to use this tool:**
28
- - **ALWAYS** before starting any task (even simple ones)
29
- - **ALWAYS** when you need to do any arithmetic or counting
30
- - **ALWAYS** after reading files or getting search results to process what you learned
31
- - **FREQUENTLY** between steps to track progress and plan next actions
32
-
33
- This is your private thinking space - use it liberally to enhance your problem-solving capabilities. Recording
34
- your thoughts helps you maintain context across multiple steps and remember important information throughout your task.
35
-
36
- When and how to use this tool:
37
-
38
- 1. **Before starting any complex task**: Write down your understanding of the problem, break it into smaller
39
- sub-tasks, and create a step-by-step plan. Example:
40
- - "The user wants me to refactor this codebase. Let me first understand the structure..."
41
- - "I need to: 1) Analyze current architecture, 2) Identify pain points, 3) Propose changes..."
42
-
43
- 2. **For arithmetic and calculations**: Work through math problems step by step. Example:
44
- - "If we have 150 requests/second and each takes 20ms, that's 150 * 0.02 = 3 seconds of CPU time..."
45
- - "Converting 2GB to bytes: 2 * 1024 * 1024 * 1024 = 2,147,483,648 bytes"
46
-
47
- 3. **After completing sub-tasks**: Summarize what you've accomplished and what remains. Example:
48
- - "I've successfully implemented the authentication module. Next, I need to integrate it with the API..."
49
- - "Fixed 3 out of 5 bugs. Remaining: memory leak in parser, race condition in worker thread"
50
-
51
- 4. **When encountering complexity**: Break down complex logic or decisions. Example:
52
- - "This function has multiple edge cases. Let me list them: null input, empty array, negative numbers..."
53
- - "The user's request is ambiguous. Possible interpretations: A) modify existing code, B) create new module..."
54
-
55
- 5. **For remembering context**: Store important information you'll need later. Example:
56
- - "Important: The user mentioned they're using Ruby 3.2, so I can use pattern matching"
57
- - "File structure: main.rb requires from lib/, config is in config.yml"
58
-
59
- 6. **When debugging or analyzing**: Track your investigation process. Example:
60
- - "The error occurs in line 42. Let me trace backwards: function called from main(), receives data from..."
61
- - "Hypothesis: the bug might be due to timezone differences. Let me check..."
62
-
63
- 7. **For creative problem-solving**: Brainstorm multiple approaches before choosing one. Example:
64
- - "Approaches to optimize this: 1) Add caching, 2) Use parallel processing, 3) Optimize algorithm..."
65
- - "Design patterns that could work here: Factory, Observer, or maybe Strategy pattern..."
66
-
67
- **Remember: The most successful agents use this tool 5-10 times per task on average. If you haven't used this
68
- tool in the last 2-3 actions, you probably should. Using this tool is a sign of thoughtful, methodical problem
69
- solving and leads to fewer mistakes and better solutions.**
70
-
71
- Your thoughts persist throughout your session as part of the conversation history, so you can refer
72
- back to earlier thinking. Use clear formatting and organization to make it easy to reference
73
- later. Don't hesitate to think out loud - this tool is designed to augment your cognitive capabilities and help
74
- you deliver better solutions.
75
-
76
- **CRITICAL:** The Think tool takes only one parameter: thoughts. Do not include any other parameters.
77
- DESC
78
-
79
- param :thoughts,
80
- type: "string",
81
- desc: "Your thoughts, plans, calculations, or any notes you want to record",
82
- required: true
83
-
84
- def execute(**kwargs)
85
- <<~RESP
86
- Thought noted.
87
- RESP
88
- # <system-reminder>The user cannot see your thoughts. You MUST NOT stop without giving the user a response.</system-reminder>
89
- end
90
-
91
- private
92
-
93
- def validation_error(message)
94
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
95
- end
96
- end
97
- end
98
- end