swarm_memory 2.1.5 → 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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. metadata +5 -184
  4. data/lib/claude_swarm/base_executor.rb +0 -133
  5. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  6. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  7. data/lib/claude_swarm/cli.rb +0 -697
  8. data/lib/claude_swarm/commands/ps.rb +0 -215
  9. data/lib/claude_swarm/commands/show.rb +0 -139
  10. data/lib/claude_swarm/configuration.rb +0 -373
  11. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  12. data/lib/claude_swarm/json_handler.rb +0 -91
  13. data/lib/claude_swarm/mcp_generator.rb +0 -230
  14. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  15. data/lib/claude_swarm/openai/executor.rb +0 -256
  16. data/lib/claude_swarm/openai/responses.rb +0 -319
  17. data/lib/claude_swarm/orchestrator.rb +0 -878
  18. data/lib/claude_swarm/process_tracker.rb +0 -78
  19. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  20. data/lib/claude_swarm/session_path.rb +0 -42
  21. data/lib/claude_swarm/settings_generator.rb +0 -77
  22. data/lib/claude_swarm/system_utils.rb +0 -46
  23. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  24. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  25. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  27. data/lib/claude_swarm/version.rb +0 -5
  28. data/lib/claude_swarm/worktree_manager.rb +0 -475
  29. data/lib/claude_swarm/yaml_loader.rb +0 -22
  30. data/lib/claude_swarm.rb +0 -67
  31. data/lib/swarm_cli/cli.rb +0 -201
  32. data/lib/swarm_cli/command_registry.rb +0 -61
  33. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  34. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  35. data/lib/swarm_cli/commands/migrate.rb +0 -55
  36. data/lib/swarm_cli/commands/run.rb +0 -173
  37. data/lib/swarm_cli/config_loader.rb +0 -98
  38. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  39. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  40. data/lib/swarm_cli/interactive_repl.rb +0 -924
  41. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  42. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  43. data/lib/swarm_cli/migrate_options.rb +0 -54
  44. data/lib/swarm_cli/migrator.rb +0 -132
  45. data/lib/swarm_cli/options.rb +0 -151
  46. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  47. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  48. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  49. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  50. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  51. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  52. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  53. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  54. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  55. data/lib/swarm_cli/ui/icons.rb +0 -36
  56. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  57. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  58. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  59. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  60. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  61. data/lib/swarm_cli/version.rb +0 -5
  62. data/lib/swarm_cli.rb +0 -46
  63. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  64. data/lib/swarm_sdk/agent/builder.rb +0 -552
  65. data/lib/swarm_sdk/agent/chat.rb +0 -774
  66. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  67. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  68. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  69. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  70. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  71. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  72. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  73. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  75. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  76. data/lib/swarm_sdk/agent/context.rb +0 -116
  77. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  78. data/lib/swarm_sdk/agent/definition.rb +0 -477
  79. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  80. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  81. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  82. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  83. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  84. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  85. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  86. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  87. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  88. data/lib/swarm_sdk/configuration.rb +0 -135
  89. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  90. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  91. data/lib/swarm_sdk/context_compactor.rb +0 -335
  92. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  93. data/lib/swarm_sdk/context_management/context.rb +0 -328
  94. data/lib/swarm_sdk/defaults.rb +0 -196
  95. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  96. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  97. data/lib/swarm_sdk/hooks/context.rb +0 -197
  98. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  99. data/lib/swarm_sdk/hooks/error.rb +0 -29
  100. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  101. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  102. data/lib/swarm_sdk/hooks/result.rb +0 -150
  103. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  104. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  105. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  106. data/lib/swarm_sdk/log_collector.rb +0 -227
  107. data/lib/swarm_sdk/log_stream.rb +0 -127
  108. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  109. data/lib/swarm_sdk/model_aliases.json +0 -8
  110. data/lib/swarm_sdk/models.json +0 -1
  111. data/lib/swarm_sdk/models.rb +0 -120
  112. data/lib/swarm_sdk/node_context.rb +0 -245
  113. data/lib/swarm_sdk/observer/builder.rb +0 -81
  114. data/lib/swarm_sdk/observer/config.rb +0 -45
  115. data/lib/swarm_sdk/observer/manager.rb +0 -236
  116. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  117. data/lib/swarm_sdk/permissions/config.rb +0 -239
  118. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  119. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  120. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  121. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  122. data/lib/swarm_sdk/plugin.rb +0 -309
  123. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  124. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  125. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  126. data/lib/swarm_sdk/restore_result.rb +0 -65
  127. data/lib/swarm_sdk/result.rb +0 -123
  128. data/lib/swarm_sdk/snapshot.rb +0 -156
  129. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  130. data/lib/swarm_sdk/state_restorer.rb +0 -476
  131. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  132. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  133. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  134. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  135. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  136. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  141. data/lib/swarm_sdk/swarm.rb +0 -717
  142. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  143. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  144. data/lib/swarm_sdk/tools/bash.rb +0 -282
  145. data/lib/swarm_sdk/tools/clock.rb +0 -44
  146. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  147. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  148. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  149. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  150. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  151. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  152. data/lib/swarm_sdk/tools/edit.rb +0 -145
  153. data/lib/swarm_sdk/tools/glob.rb +0 -166
  154. data/lib/swarm_sdk/tools/grep.rb +0 -235
  155. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  156. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  157. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  158. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  159. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  160. data/lib/swarm_sdk/tools/read.rb +0 -261
  161. data/lib/swarm_sdk/tools/registry.rb +0 -205
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  165. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  166. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  167. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  168. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  169. data/lib/swarm_sdk/tools/think.rb +0 -98
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/utils.rb +0 -68
  174. data/lib/swarm_sdk/validation_result.rb +0 -33
  175. data/lib/swarm_sdk/version.rb +0 -5
  176. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  177. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  178. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  179. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  180. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  181. data/lib/swarm_sdk/workflow.rb +0 -554
  182. data/lib/swarm_sdk.rb +0 -524
@@ -1,205 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- # Registry for built-in SwarmSDK tools
6
- #
7
- # Maps tool names (symbols) to their RubyLLM::Tool classes.
8
- # Provides validation, lookup, and factory functionality for tool registration.
9
- #
10
- # ## Tool Creation Pattern
11
- #
12
- # Tools register themselves with their creation requirements via the `tool_factory` method.
13
- # This eliminates the need for a giant case statement in ToolConfigurator.
14
- #
15
- # Tools fall into three categories:
16
- # 1. **No params**: Simple tools with no initialization requirements (Think, Clock)
17
- # 2. **Directory only**: Tools needing working directory (Bash, Grep, Glob)
18
- # 3. **Agent context**: Tools needing agent tracking (Read, Write, Edit, MultiEdit)
19
- # 4. **Scratchpad**: Tools needing scratchpad storage instance
20
- #
21
- # @example Adding a new tool with creation requirements
22
- # # In the tool class:
23
- # class MyTool < RubyLLM::Tool
24
- # def self.creation_requirements
25
- # [:agent_name, :directory]
26
- # end
27
- # end
28
- #
29
- # # In registry:
30
- # BUILTIN_TOOLS = {
31
- # MyTool: SwarmSDK::Tools::MyTool,
32
- # }
33
- #
34
- # Note: Plugin-provided tools (e.g., memory tools) are NOT in this registry.
35
- # They are registered via SwarmSDK::PluginRegistry instead.
36
- class Registry
37
- # All available built-in tools
38
- #
39
- # Maps tool names to their classes. The class must respond to `creation_requirements`
40
- # to specify what parameters are needed for instantiation.
41
- BUILTIN_TOOLS = {
42
- Read: SwarmSDK::Tools::Read,
43
- Write: SwarmSDK::Tools::Write,
44
- Edit: SwarmSDK::Tools::Edit,
45
- MultiEdit: SwarmSDK::Tools::MultiEdit,
46
- Bash: SwarmSDK::Tools::Bash,
47
- Grep: SwarmSDK::Tools::Grep,
48
- Glob: SwarmSDK::Tools::Glob,
49
- TodoWrite: SwarmSDK::Tools::TodoWrite,
50
- ScratchpadWrite: :scratchpad, # Requires scratchpad storage instance
51
- ScratchpadRead: :scratchpad, # Requires scratchpad storage instance
52
- ScratchpadList: :scratchpad, # Requires scratchpad storage instance
53
- Think: SwarmSDK::Tools::Think,
54
- WebFetch: SwarmSDK::Tools::WebFetch,
55
- Clock: SwarmSDK::Tools::Clock,
56
- }.freeze
57
-
58
- class << self
59
- # Get tool class by name
60
- #
61
- # Note: Plugin-provided tools are NOT returned by this method.
62
- # They are managed by SwarmSDK::PluginRegistry instead.
63
- #
64
- # @param name [Symbol, String] Tool name
65
- # @return [Class, Symbol, nil] Tool class, :scratchpad marker, or nil if not found
66
- def get(name)
67
- name_sym = name.to_sym
68
- BUILTIN_TOOLS[name_sym]
69
- end
70
-
71
- # Create a tool instance using the Factory Pattern
72
- #
73
- # Uses the tool's `creation_requirements` class method to determine
74
- # what parameters to pass to the constructor.
75
- #
76
- # @param name [Symbol, String] Tool name
77
- # @param context [Hash] Available context for tool creation
78
- # @option context [Symbol] :agent_name Agent identifier
79
- # @option context [String] :directory Agent's working directory
80
- # @option context [Object] :scratchpad_storage Scratchpad storage instance
81
- # @return [RubyLLM::Tool] Instantiated tool
82
- # @raise [ConfigurationError] If tool is unknown or has unmet requirements
83
- def create(name, context = {})
84
- name_sym = name.to_sym
85
- tool_entry = BUILTIN_TOOLS[name_sym]
86
-
87
- raise ConfigurationError, "Unknown tool: #{name}" unless tool_entry
88
-
89
- # Handle scratchpad tools specially (they use factory methods)
90
- if tool_entry == :scratchpad
91
- return create_scratchpad_tool(name_sym, context[:scratchpad_storage])
92
- end
93
-
94
- # Get the tool class and its requirements
95
- tool_class = tool_entry
96
-
97
- # Check if tool defines creation requirements
98
- if tool_class.respond_to?(:creation_requirements)
99
- requirements = tool_class.creation_requirements
100
- params = extract_params(requirements, context, name)
101
- tool_class.new(**params)
102
- else
103
- # No requirements - simple instantiation
104
- tool_class.new
105
- end
106
- end
107
-
108
- # Get multiple tool classes by names
109
- #
110
- # @param names [Array<Symbol, String>] Tool names
111
- # @return [Array<Class>] Array of tool classes
112
- # @raise [ConfigurationError] If any tool name is invalid
113
- def get_many(names)
114
- names.map do |name|
115
- tool_class = get(name)
116
- unless tool_class
117
- raise ConfigurationError,
118
- "Unknown tool: #{name}. Available tools: #{available_names.join(", ")}"
119
- end
120
-
121
- tool_class
122
- end
123
- end
124
-
125
- # Check if a tool exists
126
- #
127
- # Note: Only checks built-in tools. Plugin-provided tools are checked
128
- # via SwarmSDK::PluginRegistry.plugin_tool?() instead.
129
- #
130
- # @param name [Symbol, String] Tool name
131
- # @return [Boolean]
132
- def exists?(name)
133
- name_sym = name.to_sym
134
- BUILTIN_TOOLS.key?(name_sym)
135
- end
136
-
137
- # Get all available built-in tool names
138
- #
139
- # Note: Does NOT include plugin-provided tools. To get all available tools
140
- # including plugins, combine with SwarmSDK::PluginRegistry.tools.
141
- #
142
- # @return [Array<Symbol>]
143
- def available_names
144
- BUILTIN_TOOLS.keys
145
- end
146
-
147
- # Validate tool names
148
- #
149
- # @param names [Array<Symbol, String>] Tool names to validate
150
- # @return [Array<Symbol>] Invalid tool names
151
- def validate(names)
152
- names.reject { |name| exists?(name) }
153
- end
154
-
155
- private
156
-
157
- # Extract required parameters from context
158
- #
159
- # @param requirements [Array<Symbol>] Required parameter names
160
- # @param context [Hash] Available context
161
- # @param tool_name [Symbol] Tool name for error messages
162
- # @return [Hash] Parameters to pass to tool constructor
163
- # @raise [ConfigurationError] If required parameter is missing
164
- def extract_params(requirements, context, tool_name)
165
- params = {}
166
-
167
- requirements.each do |req|
168
- unless context.key?(req)
169
- raise ConfigurationError,
170
- "Tool #{tool_name} requires #{req} but it was not provided in context"
171
- end
172
-
173
- params[req] = context[req]
174
- end
175
-
176
- params
177
- end
178
-
179
- # Create a scratchpad tool using its factory method
180
- #
181
- # @param name [Symbol] Scratchpad tool name
182
- # @param storage [Object] Scratchpad storage instance
183
- # @return [RubyLLM::Tool] Instantiated scratchpad tool
184
- # @raise [ConfigurationError] If storage is not provided
185
- def create_scratchpad_tool(name, storage)
186
- unless storage
187
- raise ConfigurationError,
188
- "Scratchpad tool #{name} requires scratchpad_storage in context"
189
- end
190
-
191
- case name
192
- when :ScratchpadWrite
193
- Tools::Scratchpad::ScratchpadWrite.create_for_scratchpad(storage)
194
- when :ScratchpadRead
195
- Tools::Scratchpad::ScratchpadRead.create_for_scratchpad(storage)
196
- when :ScratchpadList
197
- Tools::Scratchpad::ScratchpadList.create_for_scratchpad(storage)
198
- else
199
- raise ConfigurationError, "Unknown scratchpad tool: #{name}"
200
- end
201
- end
202
- end
203
- end
204
- end
205
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Scratchpad
6
- # Tool for listing scratchpad entries
7
- #
8
- # Shows all entries in the shared scratchpad with their metadata.
9
- # All agents in the swarm share the same scratchpad.
10
- class ScratchpadList < RubyLLM::Tool
11
- define_method(:name) { "ScratchpadList" }
12
-
13
- description <<~DESC
14
- List all entries in scratchpad with their metadata.
15
-
16
- ## When to Use ScratchpadList
17
-
18
- Use ScratchpadList to:
19
- - Discover what content is available in the scratchpad
20
- - Check what other agents have stored
21
- - Find relevant entries before reading them
22
- - Review all stored outputs and analysis
23
- - Check entry sizes and last update times
24
-
25
- ## Best Practices
26
-
27
- - Use this before ScratchpadRead if you don't know what's stored
28
- - Filter by prefix to narrow down results (e.g., 'notes/' lists all notes)
29
- - Shows path, title, size, and last updated time for each entry
30
- - Any agent can see all scratchpad entries
31
- - Helps coordinate multi-agent workflows
32
-
33
- ## Examples
34
-
35
- - List all entries: (no prefix parameter)
36
- - List notes only: prefix='notes/'
37
- - List analysis results: prefix='analysis/'
38
- DESC
39
-
40
- param :prefix,
41
- desc: "Optional prefix to filter entries (e.g., 'notes/' to list all entries under notes/)",
42
- required: false
43
-
44
- class << self
45
- # Create a ScratchpadList tool for a specific scratchpad storage instance
46
- #
47
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
48
- # @return [ScratchpadList] Tool instance
49
- def create_for_scratchpad(scratchpad_storage)
50
- new(scratchpad_storage)
51
- end
52
- end
53
-
54
- # Initialize with scratchpad storage instance
55
- #
56
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
57
- def initialize(scratchpad_storage)
58
- super() # Call RubyLLM::Tool's initialize
59
- @scratchpad_storage = scratchpad_storage
60
- end
61
-
62
- # Execute the tool
63
- #
64
- # @param prefix [String, nil] Optional prefix to filter entries
65
- # @return [String] Formatted list of entries
66
- def execute(prefix: nil)
67
- entries = scratchpad_storage.list(prefix: prefix)
68
-
69
- if entries.empty?
70
- prefix_msg = prefix ? " with prefix '#{prefix}'" : ""
71
- return "No entries found in scratchpad#{prefix_msg}"
72
- end
73
-
74
- result = []
75
- prefix_msg = prefix ? " with prefix '#{prefix}'" : ""
76
- result << "Scratchpad entries#{prefix_msg} (#{entries.size} #{entries.size == 1 ? "entry" : "entries"}):"
77
- result << ""
78
-
79
- entries.each do |entry|
80
- time_str = entry[:updated_at].strftime("%Y-%m-%d %H:%M:%S")
81
- result << " scratchpad://#{entry[:path]}"
82
- result << " Title: #{entry[:title]}"
83
- result << " Size: #{format_bytes(entry[:size])}"
84
- result << " Updated: #{time_str}"
85
- result << ""
86
- end
87
-
88
- result.join("\n").rstrip
89
- rescue ArgumentError => e
90
- validation_error(e.message)
91
- end
92
-
93
- private
94
-
95
- attr_reader :scratchpad_storage
96
-
97
- def validation_error(message)
98
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
99
- end
100
-
101
- # Format bytes to human-readable size
102
- #
103
- # @param bytes [Integer] Number of bytes
104
- # @return [String] Formatted size
105
- def format_bytes(bytes)
106
- if bytes >= 1_000_000
107
- "#{(bytes.to_f / 1_000_000).round(1)}MB"
108
- elsif bytes >= 1_000
109
- "#{(bytes.to_f / 1_000).round(1)}KB"
110
- else
111
- "#{bytes}B"
112
- end
113
- end
114
- end
115
- end
116
- end
117
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Scratchpad
6
- # Tool for reading content from scratchpad storage
7
- #
8
- # Retrieves content stored by any agent using scratchpad_write.
9
- # All agents in the swarm share the same scratchpad.
10
- class ScratchpadRead < RubyLLM::Tool
11
- define_method(:name) { "ScratchpadRead" }
12
-
13
- description <<~DESC
14
- Read content from scratchpad.
15
-
16
- ## When to Use ScratchpadRead
17
-
18
- Use ScratchpadRead to:
19
- - Retrieve previously stored content and outputs
20
- - Access detailed analysis or results from earlier steps
21
- - Read messages or notes left by other agents
22
- - Access cached computed data
23
- - Retrieve content that was too long for direct responses
24
-
25
- ## Best Practices
26
-
27
- - Any agent can read any scratchpad content
28
- - Content is returned with line numbers for easy reference
29
- - Use ScratchpadList first if you don't know what's stored
30
- - Scratchpad data is temporary and lost when swarm ends
31
- - For persistent data, use MemoryRead instead
32
-
33
- ## Examples
34
-
35
- - Read status: file_path='status'
36
- - Read analysis: file_path='api_analysis'
37
- - Read agent notes: file_path='notes/backend'
38
- DESC
39
-
40
- param :file_path,
41
- desc: "Path to read from scratchpad (e.g., 'status', 'result', 'notes/agent_x')",
42
- required: true
43
-
44
- class << self
45
- # Create a ScratchpadRead tool for a specific scratchpad storage instance
46
- #
47
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
48
- # @return [ScratchpadRead] Tool instance
49
- def create_for_scratchpad(scratchpad_storage)
50
- new(scratchpad_storage)
51
- end
52
- end
53
-
54
- # Initialize with scratchpad storage instance
55
- #
56
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
57
- def initialize(scratchpad_storage)
58
- super() # Call RubyLLM::Tool's initialize
59
- @scratchpad_storage = scratchpad_storage
60
- end
61
-
62
- # Execute the tool
63
- #
64
- # @param file_path [String] Path to read from
65
- # @return [String] Content at the path with line numbers, or error message
66
- def execute(file_path:)
67
- content = scratchpad_storage.read(file_path: file_path)
68
- format_with_line_numbers(content)
69
- rescue ArgumentError => e
70
- validation_error(e.message)
71
- end
72
-
73
- private
74
-
75
- attr_reader :scratchpad_storage
76
-
77
- def validation_error(message)
78
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
79
- end
80
-
81
- # Format content with line numbers (same format as Read tool)
82
- #
83
- # @param content [String] Content to format
84
- # @return [String] Content with line numbers
85
- def format_with_line_numbers(content)
86
- lines = content.lines
87
- output_lines = lines.each_with_index.map do |line, idx|
88
- line_number = idx + 1
89
- display_line = line.chomp
90
- "#{line_number.to_s.rjust(6)}→#{display_line}"
91
- end
92
- output_lines.join("\n")
93
- end
94
- end
95
- end
96
- end
97
- end
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Scratchpad
6
- # Tool for writing content to scratchpad storage
7
- #
8
- # Stores content in volatile, shared storage for temporary communication.
9
- # All agents in the swarm share the same scratchpad.
10
- # Data is lost when the process ends (not persisted).
11
- class ScratchpadWrite < RubyLLM::Tool
12
- define_method(:name) { "ScratchpadWrite" }
13
-
14
- description <<~DESC
15
- Store content in scratchpad for temporary cross-agent communication.
16
-
17
- ## When to Use Scratchpad
18
-
19
- Use ScratchpadWrite to:
20
- - Store detailed outputs, analysis, or results that are too long for direct responses
21
- - Share information that would otherwise clutter your responses
22
- - Store intermediate results during multi-step tasks
23
- - Leave coordination messages for other agents
24
- - Cache computed data for quick retrieval
25
-
26
- ## Best Practices
27
-
28
- - Choose simple, descriptive paths: 'status', 'result', 'notes/agent_x'
29
- - Use hierarchical paths for organization: 'analysis/step1', 'analysis/step2'
30
- - Keep entries focused - one piece of information per entry
31
- - Any agent can read scratchpad content
32
- - Data is lost when the swarm ends (use MemoryWrite for persistent storage)
33
- - Maximum 1MB per entry
34
-
35
- ## Examples
36
-
37
- Good paths: 'status', 'api_analysis', 'test_results', 'notes/backend'
38
- Bad paths: 'scratch/temp/file123.txt', 'output.log'
39
- DESC
40
-
41
- param :file_path,
42
- desc: "Simple path for the content (e.g., 'status', 'result', 'notes/agent_x')",
43
- required: true
44
-
45
- param :content,
46
- desc: "Content to store in scratchpad (max 1MB per entry)",
47
- required: true
48
-
49
- param :title,
50
- desc: "Brief title describing the content",
51
- required: true
52
-
53
- class << self
54
- # Create a ScratchpadWrite tool for a specific scratchpad storage instance
55
- #
56
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
57
- # @return [ScratchpadWrite] Tool instance
58
- def create_for_scratchpad(scratchpad_storage)
59
- new(scratchpad_storage)
60
- end
61
- end
62
-
63
- # Initialize with scratchpad storage instance
64
- #
65
- # @param scratchpad_storage [Stores::ScratchpadStorage] Shared scratchpad storage instance
66
- def initialize(scratchpad_storage)
67
- super() # Call RubyLLM::Tool's initialize
68
- @scratchpad_storage = scratchpad_storage
69
- end
70
-
71
- # Execute the tool
72
- #
73
- # @param file_path [String] Path to store content
74
- # @param content [String] Content to store
75
- # @param title [String] Brief title
76
- # @return [String] Success message with path and size
77
- def execute(file_path:, content:, title:)
78
- entry = scratchpad_storage.write(file_path: file_path, content: content, title: title)
79
- "Stored at scratchpad://#{file_path} (#{format_bytes(entry.size)})"
80
- rescue ArgumentError => e
81
- validation_error(e.message)
82
- end
83
-
84
- private
85
-
86
- attr_reader :scratchpad_storage
87
-
88
- def validation_error(message)
89
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
90
- end
91
-
92
- # Format bytes to human-readable size
93
- #
94
- # @param bytes [Integer] Number of bytes
95
- # @return [String] Formatted size
96
- def format_bytes(bytes)
97
- if bytes >= 1_000_000
98
- "#{(bytes.to_f / 1_000_000).round(1)}MB"
99
- elsif bytes >= 1_000
100
- "#{(bytes.to_f / 1_000).round(1)}KB"
101
- else
102
- "#{bytes}B"
103
- end
104
- end
105
- end
106
- end
107
- end
108
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Tools
5
- module Stores
6
- # ReadTracker manages read-file tracking for all agents with content digest verification
7
- #
8
- # This module maintains a global registry of which files each agent has read
9
- # during their conversation along with SHA256 digests of the content. This enables
10
- # enforcement of the "read-before-write" and "read-before-edit" rules that ensure
11
- # agents have context before modifying files, AND prevents editing files that have
12
- # changed externally since being read.
13
- #
14
- # Each agent maintains an independent map of read files to content digests.
15
- module ReadTracker
16
- @read_files = {} # { agent_id => { file_path => sha256_digest } }
17
- @mutex = Mutex.new
18
-
19
- class << self
20
- # Register that an agent has read a file with content digest
21
- #
22
- # @param agent_id [Symbol] The agent identifier
23
- # @param file_path [String] The absolute path to the file
24
- # @param content [String] File content (for digest calculation)
25
- # @return [String] The calculated SHA256 digest
26
- def register_read(agent_id, file_path, content)
27
- @mutex.synchronize do
28
- @read_files[agent_id] ||= {}
29
- digest = Digest::SHA256.hexdigest(content)
30
- @read_files[agent_id][File.expand_path(file_path)] = digest
31
- digest
32
- end
33
- end
34
-
35
- # Check if an agent has read a file AND content hasn't changed
36
- #
37
- # @param agent_id [Symbol] The agent identifier
38
- # @param file_path [String] The absolute path to the file
39
- # @return [Boolean] true if agent read file and content matches
40
- def file_read?(agent_id, file_path)
41
- @mutex.synchronize do
42
- return false unless @read_files[agent_id]
43
-
44
- expanded_path = File.expand_path(file_path)
45
- stored_digest = @read_files[agent_id][expanded_path]
46
- return false unless stored_digest
47
-
48
- # Check if file still exists and matches stored digest
49
- return false unless File.exist?(expanded_path)
50
-
51
- current_digest = Digest::SHA256.hexdigest(File.read(expanded_path))
52
- current_digest == stored_digest
53
- end
54
- end
55
-
56
- # Get all read files with digests for snapshot
57
- #
58
- # @param agent_id [Symbol] The agent identifier
59
- # @return [Hash] { file_path => digest }
60
- def get_read_files(agent_id)
61
- @mutex.synchronize do
62
- @read_files[agent_id]&.dup || {}
63
- end
64
- end
65
-
66
- # Restore read files with digests from snapshot
67
- #
68
- # @param agent_id [Symbol] The agent identifier
69
- # @param files_with_digests [Hash] { file_path => digest }
70
- # @return [void]
71
- def restore_read_files(agent_id, files_with_digests)
72
- @mutex.synchronize do
73
- @read_files[agent_id] = files_with_digests.dup
74
- end
75
- end
76
-
77
- # Clear read history for an agent (useful for testing)
78
- #
79
- # @param agent_id [Symbol] The agent identifier
80
- def clear(agent_id)
81
- @mutex.synchronize do
82
- @read_files.delete(agent_id)
83
- end
84
- end
85
-
86
- # Clear all read history (useful for testing)
87
- def clear_all
88
- @mutex.synchronize do
89
- @read_files.clear
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
96
- end