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.
- checksums.yaml +4 -4
- data/lib/swarm_memory/version.rb +1 -1
- metadata +5 -184
- data/lib/claude_swarm/base_executor.rb +0 -133
- data/lib/claude_swarm/claude_code_executor.rb +0 -349
- data/lib/claude_swarm/claude_mcp_server.rb +0 -78
- data/lib/claude_swarm/cli.rb +0 -697
- data/lib/claude_swarm/commands/ps.rb +0 -215
- data/lib/claude_swarm/commands/show.rb +0 -139
- data/lib/claude_swarm/configuration.rb +0 -373
- data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
- data/lib/claude_swarm/json_handler.rb +0 -91
- data/lib/claude_swarm/mcp_generator.rb +0 -230
- data/lib/claude_swarm/openai/chat_completion.rb +0 -256
- data/lib/claude_swarm/openai/executor.rb +0 -256
- data/lib/claude_swarm/openai/responses.rb +0 -319
- data/lib/claude_swarm/orchestrator.rb +0 -878
- data/lib/claude_swarm/process_tracker.rb +0 -78
- data/lib/claude_swarm/session_cost_calculator.rb +0 -209
- data/lib/claude_swarm/session_path.rb +0 -42
- data/lib/claude_swarm/settings_generator.rb +0 -77
- data/lib/claude_swarm/system_utils.rb +0 -46
- data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
- data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
- data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
- data/lib/claude_swarm/tools/task_tool.rb +0 -63
- data/lib/claude_swarm/version.rb +0 -5
- data/lib/claude_swarm/worktree_manager.rb +0 -475
- data/lib/claude_swarm/yaml_loader.rb +0 -22
- data/lib/claude_swarm.rb +0 -67
- data/lib/swarm_cli/cli.rb +0 -201
- data/lib/swarm_cli/command_registry.rb +0 -61
- data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
- data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
- data/lib/swarm_cli/commands/migrate.rb +0 -55
- data/lib/swarm_cli/commands/run.rb +0 -173
- data/lib/swarm_cli/config_loader.rb +0 -98
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
- data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
- data/lib/swarm_cli/interactive_repl.rb +0 -924
- data/lib/swarm_cli/mcp_serve_options.rb +0 -44
- data/lib/swarm_cli/mcp_tools_options.rb +0 -59
- data/lib/swarm_cli/migrate_options.rb +0 -54
- data/lib/swarm_cli/migrator.rb +0 -132
- data/lib/swarm_cli/options.rb +0 -151
- data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
- data/lib/swarm_cli/ui/components/content_block.rb +0 -120
- data/lib/swarm_cli/ui/components/divider.rb +0 -57
- data/lib/swarm_cli/ui/components/panel.rb +0 -62
- data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
- data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
- data/lib/swarm_cli/ui/formatters/number.rb +0 -58
- data/lib/swarm_cli/ui/formatters/text.rb +0 -77
- data/lib/swarm_cli/ui/formatters/time.rb +0 -73
- data/lib/swarm_cli/ui/icons.rb +0 -36
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
- data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
- data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
- data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
- data/lib/swarm_cli/version.rb +0 -5
- data/lib/swarm_cli.rb +0 -46
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
- data/lib/swarm_sdk/agent/builder.rb +0 -552
- data/lib/swarm_sdk/agent/chat.rb +0 -774
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
- data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
- data/lib/swarm_sdk/agent/context.rb +0 -116
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -477
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/builders/base_builder.rb +0 -409
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
- data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
- data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
- data/lib/swarm_sdk/concerns/validatable.rb +0 -55
- data/lib/swarm_sdk/configuration/parser.rb +0 -353
- data/lib/swarm_sdk/configuration/translator.rb +0 -255
- data/lib/swarm_sdk/configuration.rb +0 -135
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
- data/lib/swarm_sdk/context_compactor.rb +0 -335
- data/lib/swarm_sdk/context_management/builder.rb +0 -128
- data/lib/swarm_sdk/context_management/context.rb +0 -328
- data/lib/swarm_sdk/defaults.rb +0 -196
- data/lib/swarm_sdk/events_to_messages.rb +0 -199
- data/lib/swarm_sdk/hooks/adapter.rb +0 -359
- data/lib/swarm_sdk/hooks/context.rb +0 -197
- data/lib/swarm_sdk/hooks/definition.rb +0 -80
- data/lib/swarm_sdk/hooks/error.rb +0 -29
- data/lib/swarm_sdk/hooks/executor.rb +0 -146
- data/lib/swarm_sdk/hooks/registry.rb +0 -147
- data/lib/swarm_sdk/hooks/result.rb +0 -150
- data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
- data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
- data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
- data/lib/swarm_sdk/log_collector.rb +0 -227
- data/lib/swarm_sdk/log_stream.rb +0 -127
- data/lib/swarm_sdk/markdown_parser.rb +0 -75
- data/lib/swarm_sdk/model_aliases.json +0 -8
- data/lib/swarm_sdk/models.json +0 -1
- data/lib/swarm_sdk/models.rb +0 -120
- data/lib/swarm_sdk/node_context.rb +0 -245
- data/lib/swarm_sdk/observer/builder.rb +0 -81
- data/lib/swarm_sdk/observer/config.rb +0 -45
- data/lib/swarm_sdk/observer/manager.rb +0 -236
- data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
- data/lib/swarm_sdk/permissions/config.rb +0 -239
- data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
- data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
- data/lib/swarm_sdk/permissions/validator.rb +0 -173
- data/lib/swarm_sdk/permissions_builder.rb +0 -122
- data/lib/swarm_sdk/plugin.rb +0 -309
- data/lib/swarm_sdk/plugin_registry.rb +0 -101
- data/lib/swarm_sdk/proc_helpers.rb +0 -53
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
- data/lib/swarm_sdk/restore_result.rb +0 -65
- data/lib/swarm_sdk/result.rb +0 -123
- data/lib/swarm_sdk/snapshot.rb +0 -156
- data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
- data/lib/swarm_sdk/state_restorer.rb +0 -476
- data/lib/swarm_sdk/state_snapshot.rb +0 -334
- data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
- data/lib/swarm_sdk/swarm/builder.rb +0 -249
- data/lib/swarm_sdk/swarm/executor.rb +0 -213
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
- data/lib/swarm_sdk/swarm.rb +0 -717
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/bash.rb +0 -282
- data/lib/swarm_sdk/tools/clock.rb +0 -44
- data/lib/swarm_sdk/tools/delegate.rb +0 -267
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
- data/lib/swarm_sdk/tools/edit.rb +0 -145
- data/lib/swarm_sdk/tools/glob.rb +0 -166
- data/lib/swarm_sdk/tools/grep.rb +0 -235
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
- data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
- data/lib/swarm_sdk/tools/read.rb +0 -261
- data/lib/swarm_sdk/tools/registry.rb +0 -205
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
- data/lib/swarm_sdk/tools/think.rb +0 -98
- data/lib/swarm_sdk/tools/todo_write.rb +0 -235
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/utils.rb +0 -68
- data/lib/swarm_sdk/validation_result.rb +0 -33
- data/lib/swarm_sdk/version.rb +0 -5
- data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
- data/lib/swarm_sdk/workflow/builder.rb +0 -143
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
- data/lib/swarm_sdk/workflow.rb +0 -554
- 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
|