claude_swarm 1.0.10 → 1.0.11

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG.md → CHANGELOG.claude-swarm.md} +3 -0
  3. data/CLAUDE.md +0 -1
  4. data/decisions/2025-11-22-001-global-agent-registry.md +172 -0
  5. data/docs/v2/CHANGELOG.swarm_cli.md +12 -0
  6. data/docs/v2/CHANGELOG.swarm_memory.md +139 -0
  7. data/docs/v2/CHANGELOG.swarm_sdk.md +249 -1
  8. data/docs/v2/README.md +15 -5
  9. data/docs/v2/guides/complete-tutorial.md +93 -7
  10. data/docs/v2/guides/getting-started.md +3 -1
  11. data/docs/v2/guides/memory-adapters.md +41 -0
  12. data/docs/v2/guides/{migrating-to-2.3.md → migrating-to-2.x.md} +213 -8
  13. data/docs/v2/guides/plugins.md +52 -5
  14. data/docs/v2/guides/rails-integration.md +6 -0
  15. data/docs/v2/guides/swarm-memory.md +2 -13
  16. data/docs/v2/reference/cli.md +0 -1
  17. data/docs/v2/reference/configuration_reference.md +300 -0
  18. data/docs/v2/reference/event_payload_structures.md +26 -4
  19. data/docs/v2/reference/ruby-dsl.md +457 -4
  20. data/docs/v2/reference/swarm_memory_technical_details.md +7 -29
  21. data/docs/v2/reference/yaml.md +2 -2
  22. data/lib/claude_swarm/mcp_generator.rb +1 -1
  23. data/lib/claude_swarm/orchestrator.rb +8 -1
  24. data/lib/claude_swarm/version.rb +1 -1
  25. data/lib/swarm_cli/version.rb +1 -1
  26. data/lib/swarm_memory/core/semantic_index.rb +10 -2
  27. data/lib/swarm_memory/core/storage.rb +7 -2
  28. data/lib/swarm_memory/dsl/memory_config.rb +37 -0
  29. data/lib/swarm_memory/integration/sdk_plugin.rb +120 -27
  30. data/lib/swarm_memory/optimization/defragmenter.rb +1 -1
  31. data/lib/swarm_memory/prompts/memory_researcher.md.erb +0 -1
  32. data/lib/swarm_memory/tools/load_skill.rb +0 -1
  33. data/lib/swarm_memory/tools/memory_edit.rb +2 -1
  34. data/lib/swarm_memory/tools/memory_read.rb +1 -1
  35. data/lib/swarm_memory/version.rb +1 -1
  36. data/lib/swarm_memory.rb +7 -5
  37. data/lib/swarm_sdk/agent/chat.rb +1 -1
  38. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +4 -0
  39. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +1 -1
  40. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +38 -4
  41. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +2 -2
  42. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +3 -5
  43. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +48 -0
  44. data/lib/swarm_sdk/agent/context.rb +1 -2
  45. data/lib/swarm_sdk/agent/definition.rb +3 -3
  46. data/lib/swarm_sdk/agent/system_prompt_builder.rb +1 -1
  47. data/lib/swarm_sdk/agent_registry.rb +146 -0
  48. data/lib/swarm_sdk/builders/base_builder.rb +91 -12
  49. data/lib/swarm_sdk/config.rb +302 -0
  50. data/lib/swarm_sdk/configuration/parser.rb +22 -2
  51. data/lib/swarm_sdk/configuration.rb +13 -4
  52. data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
  53. data/lib/swarm_sdk/custom_tool_registry.rb +226 -0
  54. data/lib/swarm_sdk/hooks/adapter.rb +3 -3
  55. data/lib/swarm_sdk/hooks/shell_executor.rb +4 -3
  56. data/lib/swarm_sdk/models.json +4333 -1
  57. data/lib/swarm_sdk/models.rb +43 -2
  58. data/lib/swarm_sdk/plugin.rb +2 -2
  59. data/lib/swarm_sdk/result.rb +52 -0
  60. data/lib/swarm_sdk/swarm/agent_initializer.rb +1 -1
  61. data/lib/swarm_sdk/swarm/hook_triggers.rb +1 -0
  62. data/lib/swarm_sdk/swarm/logging_callbacks.rb +1 -0
  63. data/lib/swarm_sdk/swarm/tool_configurator.rb +18 -4
  64. data/lib/swarm_sdk/swarm.rb +76 -13
  65. data/lib/swarm_sdk/tools/bash.rb +7 -9
  66. data/lib/swarm_sdk/tools/glob.rb +5 -5
  67. data/lib/swarm_sdk/tools/read.rb +8 -8
  68. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +4 -3
  69. data/lib/swarm_sdk/tools/web_fetch.rb +20 -18
  70. data/lib/swarm_sdk/version.rb +1 -1
  71. data/lib/swarm_sdk/workflow/builder.rb +49 -0
  72. data/lib/swarm_sdk/workflow/node_builder.rb +4 -2
  73. data/lib/swarm_sdk/workflow/transformer_executor.rb +4 -3
  74. data/lib/swarm_sdk.rb +261 -105
  75. data/swarm_cli.gemspec +1 -1
  76. data/swarm_memory.gemspec +8 -3
  77. data/swarm_sdk.gemspec +4 -4
  78. data/team_full.yml +104 -300
  79. metadata +9 -5
  80. data/lib/swarm_memory/tools/memory_multi_edit.rb +0 -281
  81. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -1,281 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmMemory
4
- module Tools
5
- # Tool for performing multiple edits to a memory entry
6
- #
7
- # Applies multiple edit operations sequentially to a single memory entry.
8
- # Each edit sees the result of all previous edits, allowing for
9
- # coordinated multi-step transformations.
10
- # Each agent has its own isolated memory storage.
11
- class MemoryMultiEdit < RubyLLM::Tool
12
- description <<~DESC
13
- Perform multiple exact string replacements in a single memory entry (applies edits sequentially).
14
-
15
- REQUIRED: Provide BOTH parameters - file_path and edits_json.
16
-
17
- **Required Parameters:**
18
- - file_path (REQUIRED): Path to memory entry - MUST start with concept/, fact/, skill/, or experience/
19
- - edits_json (REQUIRED): JSON array of edit operations - each must have old_string, new_string, and optionally replace_all
20
-
21
- **MEMORY STRUCTURE (4 Fixed Categories Only):**
22
- - concept/{domain}/** - Abstract ideas
23
- - fact/{subfolder}/** - Concrete information
24
- - skill/{domain}/** - Procedures
25
- - experience/** - Lessons
26
- INVALID: documentation/, reference/, project/, code/, parallel/
27
-
28
- **JSON Format:**
29
- ```json
30
- [
31
- {"old_string": "text to find", "new_string": "replacement text", "replace_all": false},
32
- {"old_string": "another find", "new_string": "another replace", "replace_all": true}
33
- ]
34
- ```
35
-
36
- **CRITICAL - Before Using This Tool:**
37
- 1. You MUST use MemoryRead on the entry first - edits without reading will FAIL
38
- 2. Copy text exactly from MemoryRead output, EXCLUDING the line number prefix
39
- 3. Line number format: " 123→actual content" - only use text AFTER the arrow
40
- 4. Edits are applied SEQUENTIALLY - later edits see results of earlier edits
41
- 5. If ANY edit fails, NO changes are saved (all-or-nothing)
42
-
43
- **How Sequential Edits Work:**
44
- ```
45
- Original: "status: pending, priority: low"
46
-
47
- Edit 1: "pending" → "in-progress"
48
- Result: "status: in-progress, priority: low"
49
-
50
- Edit 2: "low" → "high" (sees Edit 1's result)
51
- Final: "status: in-progress, priority: high"
52
- ```
53
-
54
- **Use Cases:**
55
- - Making multiple coordinated changes in one operation
56
- - Updating several related fields at once
57
- - Chaining transformations where order matters
58
- - Bulk find-and-replace operations
59
-
60
- **Examples:**
61
- ```
62
- # Update multiple fields in an experience
63
- MemoryMultiEdit(
64
- file_path: "experience/api-debugging.md",
65
- edits_json: '[
66
- {"old_string": "status: in-progress", "new_string": "status: resolved"},
67
- {"old_string": "confidence: medium", "new_string": "confidence: high"}
68
- ]'
69
- )
70
-
71
- # Rename function and update calls in a concept
72
- MemoryMultiEdit(
73
- file_path: "concept/ruby/functions.md",
74
- edits_json: '[
75
- {"old_string": "def old_func_name", "new_string": "def new_func_name"},
76
- {"old_string": "old_func_name()", "new_string": "new_func_name()", "replace_all": true}
77
- ]'
78
- )
79
- ```
80
-
81
- **Important Notes:**
82
- - All edits in the array must be valid JSON objects
83
- - Each old_string must be different from its new_string
84
- - Each old_string must be unique in content UNLESS replace_all is true
85
- - Failed edit shows which previous edits succeeded
86
- - More efficient than multiple MemoryEdit calls
87
- DESC
88
-
89
- param :file_path,
90
- desc: "Path to memory entry - MUST start with concept/, fact/, skill/, or experience/ (e.g., 'experience/api-debugging.md', 'concept/ruby/functions.md')",
91
- required: true
92
-
93
- param :edits_json,
94
- type: "string",
95
- desc: <<~DESC.chomp,
96
- JSON array of edit operations. Each edit must have:
97
- old_string (exact text to replace),
98
- new_string (replacement text),
99
- and optionally replace_all (boolean, default false).
100
- Example: [{"old_string":"foo","new_string":"bar","replace_all":false}]
101
- DESC
102
- required: true
103
-
104
- # Initialize with storage instance and agent name
105
- #
106
- # @param storage [Core::Storage] Storage instance
107
- # @param agent_name [String, Symbol] Agent identifier
108
- def initialize(storage:, agent_name:)
109
- super()
110
- @storage = storage
111
- @agent_name = agent_name.to_sym
112
- end
113
-
114
- # Override name to return simple "MemoryMultiEdit"
115
- def name
116
- "MemoryMultiEdit"
117
- end
118
-
119
- # Execute the tool
120
- #
121
- # @param file_path [String] Path to memory entry
122
- # @param edits_json [String] JSON array of edit operations
123
- # @return [String] Success message or error
124
- def execute(file_path:, edits_json:)
125
- # Validate inputs
126
- return validation_error("file_path is required") if file_path.nil? || file_path.to_s.strip.empty?
127
-
128
- # Parse JSON
129
- edits = begin
130
- JSON.parse(edits_json)
131
- rescue JSON::ParserError
132
- nil
133
- end
134
-
135
- return validation_error("Invalid JSON format. Please provide a valid JSON array of edit operations.") if edits.nil?
136
-
137
- return validation_error("edits must be an array") unless edits.is_a?(Array)
138
- return validation_error("edits array cannot be empty") if edits.empty?
139
-
140
- # Read current content (this will raise ArgumentError if entry doesn't exist)
141
- content = @storage.read(file_path: file_path)
142
-
143
- # Enforce read-before-edit with content verification
144
- unless Core::StorageReadTracker.entry_read?(@agent_name, file_path, @storage)
145
- return validation_error(
146
- "Cannot edit memory entry without reading it first. " \
147
- "You must use MemoryRead on 'memory://#{file_path}' before editing it. " \
148
- "This ensures you have the current content to match against.",
149
- )
150
- end
151
-
152
- # Validate edit operations
153
- validated_edits = []
154
- edits.each_with_index do |edit, index|
155
- unless edit.is_a?(Hash)
156
- return validation_error("Edit at index #{index} must be a hash/object with old_string and new_string")
157
- end
158
-
159
- # Convert string keys to symbols for consistency
160
- edit = edit.transform_keys(&:to_sym)
161
-
162
- unless edit[:old_string]
163
- return validation_error("Edit at index #{index} missing required field 'old_string'")
164
- end
165
-
166
- unless edit[:new_string]
167
- return validation_error("Edit at index #{index} missing required field 'new_string'")
168
- end
169
-
170
- # old_string and new_string must be different
171
- if edit[:old_string] == edit[:new_string]
172
- return validation_error("Edit at index #{index}: old_string and new_string must be different")
173
- end
174
-
175
- validated_edits << {
176
- old_string: edit[:old_string].to_s,
177
- new_string: edit[:new_string].to_s,
178
- replace_all: edit[:replace_all] == true,
179
- index: index,
180
- }
181
- end
182
-
183
- # Apply edits sequentially
184
- results = []
185
- current_content = content
186
-
187
- validated_edits.each do |edit|
188
- # Check if old_string exists in current content
189
- unless current_content.include?(edit[:old_string])
190
- return error_with_results(
191
- <<~ERROR.chomp,
192
- Edit #{edit[:index]}: old_string not found in memory entry.
193
- Make sure it matches exactly, including all whitespace and indentation.
194
- Do not include line number prefixes from MemoryRead tool output.
195
- Note: This edit follows #{edit[:index]} previous edit(s) which may have changed the content.
196
- ERROR
197
- results,
198
- )
199
- end
200
-
201
- # Count occurrences
202
- occurrences = current_content.scan(edit[:old_string]).count
203
-
204
- # If not replace_all and multiple occurrences, error
205
- if !edit[:replace_all] && occurrences > 1
206
- return error_with_results(
207
- <<~ERROR.chomp,
208
- Edit #{edit[:index]}: Found #{occurrences} occurrences of old_string.
209
- Either provide more surrounding context to make the match unique, or set replace_all: true to replace all occurrences.
210
- ERROR
211
- results,
212
- )
213
- end
214
-
215
- # Perform replacement
216
- new_content = if edit[:replace_all]
217
- current_content.gsub(edit[:old_string], edit[:new_string])
218
- else
219
- current_content.sub(edit[:old_string], edit[:new_string])
220
- end
221
-
222
- # Record result
223
- replaced_count = edit[:replace_all] ? occurrences : 1
224
- results << {
225
- index: edit[:index],
226
- status: "success",
227
- occurrences: replaced_count,
228
- message: "Replaced #{replaced_count} occurrence(s)",
229
- }
230
-
231
- # Update content for next edit
232
- current_content = new_content
233
- end
234
-
235
- # Get existing entry
236
- entry = @storage.read_entry(file_path: file_path)
237
-
238
- # Write updated content back (preserving the title)
239
- @storage.write(
240
- file_path: file_path,
241
- content: current_content,
242
- title: entry.title,
243
- )
244
-
245
- # Build success message
246
- total_replacements = results.sum { |r| r[:occurrences] }
247
- message = "Successfully applied #{validated_edits.size} edit(s) to memory://#{file_path}\n"
248
- message += "Total replacements: #{total_replacements}\n\n"
249
- message += "Details:\n"
250
- results.each do |result|
251
- message += " Edit #{result[:index]}: #{result[:message]}\n"
252
- end
253
-
254
- message
255
- rescue ArgumentError => e
256
- validation_error(e.message)
257
- end
258
-
259
- private
260
-
261
- def validation_error(message)
262
- "<tool_use_error>InputValidationError: #{message}</tool_use_error>"
263
- end
264
-
265
- def error_with_results(message, results)
266
- output = "<tool_use_error>InputValidationError: #{message}\n\n"
267
-
268
- if results.any?
269
- output += "Previous successful edits before error:\n"
270
- results.each do |result|
271
- output += " Edit #{result[:index]}: #{result[:message]}\n"
272
- end
273
- output += "\n"
274
- end
275
-
276
- output += "Note: The memory entry has NOT been modified. All or nothing approach - if any edit fails, no changes are saved.</tool_use_error>"
277
- output
278
- end
279
- end
280
- end
281
- end
File without changes