claude_swarm 1.0.9 → 1.0.10
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/CHANGELOG.md +7 -0
- data/CLAUDE.md +347 -191
- data/docs/v2/CHANGELOG.swarm_cli.md +8 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +7 -1
- data/docs/v2/CHANGELOG.swarm_sdk.md +184 -9
- data/docs/v2/README.md +6 -1
- data/docs/v2/guides/complete-tutorial.md +2 -2
- data/docs/v2/guides/getting-started.md +7 -7
- data/docs/v2/guides/migrating-to-2.3.md +541 -0
- data/docs/v2/guides/snapshots.md +14 -14
- data/docs/v2/reference/architecture-flow.md +3 -3
- data/docs/v2/reference/event_payload_structures.md +1 -1
- data/docs/v2/reference/ruby-dsl.md +157 -14
- data/docs/v2/reference/yaml.md +170 -52
- data/examples/snapshot_demo.rb +2 -2
- data/lib/claude_swarm/mcp_generator.rb +7 -20
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/swarm_cli/commands/run.rb +2 -2
- data/lib/swarm_cli/config_loader.rb +11 -11
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -33
- data/lib/swarm_cli/interactive_repl.rb +2 -2
- data/lib/swarm_cli/ui/icons.rb +0 -23
- data/lib/swarm_cli/version.rb +1 -1
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +11 -34
- data/lib/swarm_memory/integration/sdk_plugin.rb +87 -7
- data/lib/swarm_memory/version.rb +1 -1
- data/lib/swarm_memory.rb +1 -1
- data/lib/swarm_sdk/agent/builder.rb +58 -0
- data/lib/swarm_sdk/agent/chat.rb +527 -1061
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/context_tracker.rb +9 -88
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +204 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/hook_integration.rb +108 -46
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +78 -0
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +233 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +1 -1
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +12 -12
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +98 -0
- data/lib/swarm_sdk/agent/context.rb +2 -2
- data/lib/swarm_sdk/agent/definition.rb +66 -154
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +4 -2
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +161 -0
- data/lib/swarm_sdk/builders/base_builder.rb +409 -0
- data/lib/swarm_sdk/concerns/cleanupable.rb +39 -0
- data/lib/swarm_sdk/concerns/snapshotable.rb +67 -0
- data/lib/swarm_sdk/concerns/validatable.rb +55 -0
- data/lib/swarm_sdk/configuration/parser.rb +353 -0
- data/lib/swarm_sdk/configuration/translator.rb +255 -0
- data/lib/swarm_sdk/configuration.rb +65 -543
- data/lib/swarm_sdk/context_compactor/token_counter.rb +3 -3
- data/lib/swarm_sdk/context_compactor.rb +6 -11
- data/lib/swarm_sdk/context_management/builder.rb +128 -0
- data/lib/swarm_sdk/context_management/context.rb +328 -0
- data/lib/swarm_sdk/defaults.rb +196 -0
- data/lib/swarm_sdk/events_to_messages.rb +18 -0
- data/lib/swarm_sdk/hooks/shell_executor.rb +2 -1
- data/lib/swarm_sdk/log_collector.rb +179 -29
- data/lib/swarm_sdk/log_stream.rb +29 -0
- data/lib/swarm_sdk/node_context.rb +1 -1
- data/lib/swarm_sdk/observer/builder.rb +81 -0
- data/lib/swarm_sdk/observer/config.rb +45 -0
- data/lib/swarm_sdk/observer/manager.rb +236 -0
- data/lib/swarm_sdk/patterns/agent_observer.rb +160 -0
- data/lib/swarm_sdk/plugin.rb +93 -3
- data/lib/swarm_sdk/snapshot.rb +6 -6
- data/lib/swarm_sdk/snapshot_from_events.rb +13 -2
- data/lib/swarm_sdk/state_restorer.rb +136 -151
- data/lib/swarm_sdk/state_snapshot.rb +65 -100
- data/lib/swarm_sdk/swarm/agent_initializer.rb +180 -136
- data/lib/swarm_sdk/swarm/builder.rb +44 -578
- data/lib/swarm_sdk/swarm/executor.rb +213 -0
- data/lib/swarm_sdk/swarm/hook_triggers.rb +150 -0
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +340 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
- data/lib/swarm_sdk/swarm/tool_configurator.rb +42 -138
- data/lib/swarm_sdk/swarm.rb +137 -680
- data/lib/swarm_sdk/tools/bash.rb +11 -3
- data/lib/swarm_sdk/tools/delegate.rb +61 -43
- data/lib/swarm_sdk/tools/edit.rb +8 -13
- data/lib/swarm_sdk/tools/glob.rb +9 -1
- data/lib/swarm_sdk/tools/grep.rb +7 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +15 -11
- data/lib/swarm_sdk/tools/path_resolver.rb +51 -2
- data/lib/swarm_sdk/tools/read.rb +11 -13
- data/lib/swarm_sdk/tools/registry.rb +122 -10
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +8 -5
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -6
- data/lib/swarm_sdk/tools/todo_write.rb +7 -0
- data/lib/swarm_sdk/tools/web_fetch.rb +3 -2
- data/lib/swarm_sdk/tools/write.rb +8 -13
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk/{node → workflow}/agent_config.rb +1 -1
- data/lib/swarm_sdk/workflow/builder.rb +143 -0
- data/lib/swarm_sdk/workflow/executor.rb +497 -0
- data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +3 -3
- data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +3 -2
- data/lib/swarm_sdk/{node_orchestrator.rb → workflow.rb} +152 -456
- data/lib/swarm_sdk.rb +33 -3
- data/rubocop/cop/security/no_reflection_methods.rb +1 -1
- data/swarm_memory.gemspec +1 -1
- data/swarm_sdk.gemspec +4 -2
- data/team_full.yml +24 -24
- metadata +35 -11
- data/lib/swarm_memory/chat_extension.rb +0 -34
- data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -589
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
# Migrating to SwarmSDK v2.3.0
|
|
2
|
+
|
|
3
|
+
This guide covers all breaking changes and migration steps for upgrading from SwarmSDK v2.2.x to v2.3.0.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
SwarmSDK v2.3.0 introduces significant architectural improvements:
|
|
8
|
+
|
|
9
|
+
- **Swarm/Workflow API Separation** - Clear distinction between single-swarm and multi-stage workflows
|
|
10
|
+
- **Delegation Tool Rebranding** - `WorkWith*` instead of `DelegateTaskTo*`
|
|
11
|
+
- **Agent::Chat Abstraction Layer** - Improved encapsulation of RubyLLM internals
|
|
12
|
+
- **Snapshot Version 2.1.0** - Plugin state support and metadata restructuring
|
|
13
|
+
- **Observer Module** - Event-driven parallel agent execution (new feature)
|
|
14
|
+
- **Context Management DSL** - Custom context warning handlers (new feature)
|
|
15
|
+
- **Non-blocking Execution** - Async execution with cancellation support (new feature)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Priority: Critical Breaking Changes
|
|
20
|
+
|
|
21
|
+
### 1. Delegation Tool Rebranding
|
|
22
|
+
|
|
23
|
+
**What Changed:**
|
|
24
|
+
- Tool names: `DelegateTaskTo*` → `WorkWith*`
|
|
25
|
+
- Parameter: `task:` → `message:`
|
|
26
|
+
- Description emphasizes collaboration over task delegation
|
|
27
|
+
|
|
28
|
+
**Before (v2.2.x):**
|
|
29
|
+
```ruby
|
|
30
|
+
# Tool call
|
|
31
|
+
DelegateTaskToBackend(task: "Build the authentication API")
|
|
32
|
+
|
|
33
|
+
# In agent conversations
|
|
34
|
+
"I'll delegate this to Backend using DelegateTaskToBackend"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**After (v2.3.0):**
|
|
38
|
+
```ruby
|
|
39
|
+
# Tool call
|
|
40
|
+
WorkWithBackend(message: "Build the authentication API")
|
|
41
|
+
|
|
42
|
+
# In agent conversations
|
|
43
|
+
"I'll work with Backend using WorkWithBackend"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Migration Steps:**
|
|
47
|
+
|
|
48
|
+
1. **Update tool references in your code:**
|
|
49
|
+
```ruby
|
|
50
|
+
# Before
|
|
51
|
+
expect(agent.has_tool?(:DelegateTaskToBackend)).to be true
|
|
52
|
+
|
|
53
|
+
# After
|
|
54
|
+
expect(agent.has_tool?(:WorkWithBackend)).to be true
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. **Update parameter names:**
|
|
58
|
+
```ruby
|
|
59
|
+
# Before
|
|
60
|
+
result = DelegateTaskToBackend(task: "Build API")
|
|
61
|
+
|
|
62
|
+
# After
|
|
63
|
+
result = WorkWithBackend(message: "Build API")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. **Update documentation and prompts:**
|
|
67
|
+
```ruby
|
|
68
|
+
# Before - in system prompts
|
|
69
|
+
"Use DelegateTaskToBackend when you need help with APIs"
|
|
70
|
+
|
|
71
|
+
# After
|
|
72
|
+
"Use WorkWithBackend when you need to collaborate on APIs"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
4. **Canonical tool name generation:**
|
|
76
|
+
```ruby
|
|
77
|
+
# Use the canonical method
|
|
78
|
+
tool_name = SwarmSDK::Tools::Delegate.tool_name_for(:backend)
|
|
79
|
+
# Returns "WorkWithBackend"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 2. Agent::Chat Abstraction Layer
|
|
85
|
+
|
|
86
|
+
**What Changed:**
|
|
87
|
+
- Chat no longer inherits from RubyLLM::Chat (composition over inheritance)
|
|
88
|
+
- Direct access to `.tools`, `.messages`, `.model` removed
|
|
89
|
+
- New abstraction methods provide controlled access
|
|
90
|
+
|
|
91
|
+
**Before (v2.2.x):**
|
|
92
|
+
```ruby
|
|
93
|
+
agent = swarm.agent(:backend)
|
|
94
|
+
|
|
95
|
+
# Direct access to RubyLLM internals
|
|
96
|
+
agent.tools.key?(:Read) # Check tool existence
|
|
97
|
+
agent.tools.keys # List all tools
|
|
98
|
+
agent.model.id # Get model ID
|
|
99
|
+
agent.model.provider # Get provider
|
|
100
|
+
agent.messages.count # Count messages
|
|
101
|
+
agent.messages # Access messages array
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**After (v2.3.0):**
|
|
105
|
+
```ruby
|
|
106
|
+
agent = swarm.agent(:backend)
|
|
107
|
+
|
|
108
|
+
# SwarmSDK abstraction API
|
|
109
|
+
agent.has_tool?(:Read) # Check tool existence
|
|
110
|
+
agent.tool_names # List all tools
|
|
111
|
+
agent.model_id # Get model ID
|
|
112
|
+
agent.model_provider # Get provider
|
|
113
|
+
agent.message_count # Count messages
|
|
114
|
+
agent.messages # Safe copy of messages
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Migration Table:**
|
|
118
|
+
|
|
119
|
+
| Old API (v2.2.x) | New API (v2.3.0) |
|
|
120
|
+
|------------------|------------------|
|
|
121
|
+
| `chat.tools.key?(:Read)` | `chat.has_tool?(:Read)` |
|
|
122
|
+
| `chat.tools.keys` | `chat.tool_names` |
|
|
123
|
+
| `chat.tools.count` | `chat.tool_count` |
|
|
124
|
+
| `chat.tools[:Read]` | Not available (use `has_tool?`) |
|
|
125
|
+
| `chat.model.id` | `chat.model_id` |
|
|
126
|
+
| `chat.model.provider` | `chat.model_provider` |
|
|
127
|
+
| `chat.model.context_window` | `chat.model_context_window` |
|
|
128
|
+
| `chat.messages.count` | `chat.message_count` |
|
|
129
|
+
| `chat.messages.any? { \|m\| m.role == :user }` | `chat.has_user_message?` |
|
|
130
|
+
| `chat.messages.last` | `chat.last_assistant_message` |
|
|
131
|
+
|
|
132
|
+
**For Plugin/Internal Code:**
|
|
133
|
+
|
|
134
|
+
If you're writing plugins or internal modules that need direct access:
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
# Use internal access methods (not for public API consumption)
|
|
138
|
+
agent.internal_messages # Direct array of RubyLLM messages
|
|
139
|
+
agent.internal_tools # Direct hash of tool instances
|
|
140
|
+
agent.internal_model # Direct RubyLLM model object
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Why This Change:**
|
|
144
|
+
- Better encapsulation of LLM library internals
|
|
145
|
+
- Easier future migrations if RubyLLM API changes
|
|
146
|
+
- More consistent and predictable API
|
|
147
|
+
- Prevents accidental mutation of internal state
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 3. Swarm vs Workflow API Separation
|
|
152
|
+
|
|
153
|
+
**What Changed:**
|
|
154
|
+
- `SwarmSDK.build` now **ONLY** returns `Swarm`
|
|
155
|
+
- New `SwarmSDK.workflow` method for multi-stage workflows
|
|
156
|
+
- YAML uses explicit `swarm:` or `workflow:` root keys
|
|
157
|
+
- `NodeOrchestrator` class renamed to `Workflow`
|
|
158
|
+
|
|
159
|
+
**Before (v2.2.x):**
|
|
160
|
+
```ruby
|
|
161
|
+
# Single method returned either Swarm or NodeOrchestrator
|
|
162
|
+
result = SwarmSDK.build do
|
|
163
|
+
# If you used nodes, got NodeOrchestrator
|
|
164
|
+
# If not, got Swarm
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**After (v2.3.0):**
|
|
169
|
+
```ruby
|
|
170
|
+
# Explicit methods for each type
|
|
171
|
+
swarm = SwarmSDK.build do
|
|
172
|
+
name "Development Team"
|
|
173
|
+
lead :backend
|
|
174
|
+
# Cannot use nodes here - raises ConfigurationError
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
workflow = SwarmSDK.workflow do
|
|
178
|
+
name "CI Pipeline"
|
|
179
|
+
start_node :planning
|
|
180
|
+
# Must define nodes here
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Migration for DSL Users:**
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
# Before - building a workflow
|
|
188
|
+
SwarmSDK.build do
|
|
189
|
+
name "Pipeline"
|
|
190
|
+
agent(:planner) { ... }
|
|
191
|
+
node(:planning) { ... }
|
|
192
|
+
start_node :planning
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# After
|
|
196
|
+
SwarmSDK.workflow do
|
|
197
|
+
name "Pipeline"
|
|
198
|
+
agent(:planner) { ... }
|
|
199
|
+
node(:planning) { ... }
|
|
200
|
+
start_node :planning
|
|
201
|
+
end
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Migration for YAML Users:**
|
|
205
|
+
|
|
206
|
+
```yaml
|
|
207
|
+
# Before - workflow config
|
|
208
|
+
version: 2
|
|
209
|
+
swarm:
|
|
210
|
+
name: "Pipeline"
|
|
211
|
+
start_node: planning
|
|
212
|
+
agents: { ... }
|
|
213
|
+
nodes: { ... }
|
|
214
|
+
|
|
215
|
+
# After - explicit workflow key
|
|
216
|
+
version: 2
|
|
217
|
+
workflow:
|
|
218
|
+
name: "Pipeline"
|
|
219
|
+
start_node: planning
|
|
220
|
+
agents: { ... }
|
|
221
|
+
nodes: { ... }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**For Vanilla Swarm Users:**
|
|
225
|
+
No changes needed! Your code continues to work:
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
# This still works exactly the same
|
|
229
|
+
swarm = SwarmSDK.build do
|
|
230
|
+
name "Team"
|
|
231
|
+
lead :backend
|
|
232
|
+
agent(:backend) { ... }
|
|
233
|
+
end
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
# This still works exactly the same
|
|
238
|
+
version: 2
|
|
239
|
+
swarm:
|
|
240
|
+
name: "Team"
|
|
241
|
+
lead: backend
|
|
242
|
+
agents: { ... }
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### 4. Snapshot Version 2.1.0
|
|
248
|
+
|
|
249
|
+
**What Changed:**
|
|
250
|
+
- Version bumped from 1.0.0 to 2.1.0
|
|
251
|
+
- New `plugin_states` field for plugin-specific state
|
|
252
|
+
- `swarm:` metadata key renamed to `metadata:`
|
|
253
|
+
- Type field now lowercase: `"swarm"` or `"workflow"`
|
|
254
|
+
|
|
255
|
+
**Old Snapshot Format (v1.0.0):**
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"version": "1.0.0",
|
|
259
|
+
"type": "swarm",
|
|
260
|
+
"swarm": {
|
|
261
|
+
"id": "main",
|
|
262
|
+
"parent_id": null,
|
|
263
|
+
"first_message_sent": true
|
|
264
|
+
},
|
|
265
|
+
"agents": { ... },
|
|
266
|
+
"delegation_instances": { ... },
|
|
267
|
+
"read_tracking": { ... },
|
|
268
|
+
"memory_read_tracking": { ... }
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**New Snapshot Format (v2.1.0):**
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"version": "2.1.0",
|
|
276
|
+
"type": "swarm",
|
|
277
|
+
"snapshot_at": "2025-11-17T10:30:00Z",
|
|
278
|
+
"swarm_sdk_version": "2.3.0",
|
|
279
|
+
"metadata": {
|
|
280
|
+
"id": "main",
|
|
281
|
+
"parent_id": null,
|
|
282
|
+
"name": "Development Team",
|
|
283
|
+
"first_message_sent": true
|
|
284
|
+
},
|
|
285
|
+
"agents": { ... },
|
|
286
|
+
"delegation_instances": { ... },
|
|
287
|
+
"scratchpad": { ... },
|
|
288
|
+
"read_tracking": { ... },
|
|
289
|
+
"plugin_states": {
|
|
290
|
+
"backend": { "read_entries": [...] }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Migration Steps:**
|
|
296
|
+
|
|
297
|
+
1. **Cannot restore old snapshots directly** - Create new snapshots after upgrading
|
|
298
|
+
2. **Manual conversion (if absolutely needed):**
|
|
299
|
+
```ruby
|
|
300
|
+
def convert_snapshot_1_to_2(old_data)
|
|
301
|
+
{
|
|
302
|
+
version: "2.1.0",
|
|
303
|
+
type: old_data[:type] || "swarm",
|
|
304
|
+
snapshot_at: Time.now.utc.iso8601,
|
|
305
|
+
swarm_sdk_version: SwarmSDK::VERSION,
|
|
306
|
+
metadata: old_data[:swarm] || old_data[:orchestrator],
|
|
307
|
+
agents: old_data[:agents],
|
|
308
|
+
delegation_instances: old_data[:delegation_instances],
|
|
309
|
+
scratchpad: old_data[:scratchpad] || {},
|
|
310
|
+
read_tracking: old_data[:read_tracking],
|
|
311
|
+
plugin_states: convert_memory_tracking(old_data[:memory_read_tracking])
|
|
312
|
+
}
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def convert_memory_tracking(memory_tracking)
|
|
316
|
+
return {} unless memory_tracking
|
|
317
|
+
memory_tracking.transform_values do |entries|
|
|
318
|
+
{ read_entries: entries }
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
3. **Event-sourced sessions** - Use `SnapshotFromEvents.reconstruct(events)` which automatically generates v2.1.0 snapshots
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Important: Plugin Lifecycle Changes
|
|
328
|
+
|
|
329
|
+
### Plugin State Persistence
|
|
330
|
+
|
|
331
|
+
**What Changed:**
|
|
332
|
+
- Plugins now have `snapshot_agent_state` and `restore_agent_state` methods
|
|
333
|
+
- SDK no longer has direct knowledge of plugin internals
|
|
334
|
+
- `memory_read_tracking` field replaced by generic `plugin_states`
|
|
335
|
+
|
|
336
|
+
**If You Have Custom Plugins:**
|
|
337
|
+
|
|
338
|
+
```ruby
|
|
339
|
+
class MyPlugin < SwarmSDK::Plugin
|
|
340
|
+
# NEW - Snapshot your plugin's state
|
|
341
|
+
def snapshot_agent_state(agent_name)
|
|
342
|
+
{
|
|
343
|
+
custom_data: @storage[agent_name]&.to_h || {}
|
|
344
|
+
}
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# NEW - Restore your plugin's state
|
|
348
|
+
def restore_agent_state(agent_name, state)
|
|
349
|
+
@storage[agent_name]&.restore(state[:custom_data])
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# NEW - Get digest for change detection hooks
|
|
353
|
+
def get_tool_result_digest(agent_name:, tool_name:, path:)
|
|
354
|
+
return nil unless tool_name == :MyCustomRead
|
|
355
|
+
@storage[agent_name]&.digest_for(path)
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Plugin Configuration Decoupling
|
|
361
|
+
|
|
362
|
+
**What Changed:**
|
|
363
|
+
- SDK no longer knows about specific plugin configs
|
|
364
|
+
- Plugin configs stored in generic `@plugin_configs` hash
|
|
365
|
+
- Plugins handle their own YAML translation
|
|
366
|
+
|
|
367
|
+
**Agent::Definition Changes:**
|
|
368
|
+
|
|
369
|
+
```ruby
|
|
370
|
+
# Accessing plugin configuration
|
|
371
|
+
definition.plugin_config(:memory) # Returns memory plugin config
|
|
372
|
+
definition.plugin_config(:custom) # Returns custom plugin config
|
|
373
|
+
|
|
374
|
+
# Generic storage for non-SDK keys
|
|
375
|
+
definition.plugin_configs # Hash of all plugin configs
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## New Features (No Migration Required)
|
|
381
|
+
|
|
382
|
+
These are additions that don't break existing code:
|
|
383
|
+
|
|
384
|
+
### Observer Module
|
|
385
|
+
|
|
386
|
+
```ruby
|
|
387
|
+
swarm = SwarmSDK.build do
|
|
388
|
+
agent :backend { ... }
|
|
389
|
+
agent :security_monitor { ... }
|
|
390
|
+
|
|
391
|
+
# NEW - Parallel agent execution
|
|
392
|
+
observer :security_monitor do
|
|
393
|
+
on :tool_call do |event|
|
|
394
|
+
next unless event[:tool_name] == "Bash"
|
|
395
|
+
"Check security of: #{event[:arguments][:command]}"
|
|
396
|
+
end
|
|
397
|
+
timeout 30
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Context Management DSL
|
|
403
|
+
|
|
404
|
+
```ruby
|
|
405
|
+
agent :backend do
|
|
406
|
+
# NEW - Custom context warning handlers
|
|
407
|
+
context_management do
|
|
408
|
+
on :warning_60 do |ctx|
|
|
409
|
+
ctx.compress_tool_results(keep_recent: 15)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
on :warning_80 do |ctx|
|
|
413
|
+
ctx.prune_old_messages(keep_recent: 20)
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Non-blocking Execution
|
|
420
|
+
|
|
421
|
+
```ruby
|
|
422
|
+
# NEW - Async execution with cancellation
|
|
423
|
+
Sync do
|
|
424
|
+
task = swarm.execute("Build feature", wait: false)
|
|
425
|
+
|
|
426
|
+
# Cancel if needed
|
|
427
|
+
task.stop
|
|
428
|
+
|
|
429
|
+
# Wait for result
|
|
430
|
+
result = task.wait # Returns nil if cancelled
|
|
431
|
+
end
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Filtered Event Subscriptions
|
|
435
|
+
|
|
436
|
+
```ruby
|
|
437
|
+
# NEW - Subscribe to specific events
|
|
438
|
+
LogCollector.subscribe(filter: { type: "tool_call", agent: :backend }) do |event|
|
|
439
|
+
puts "Backend called tool: #{event[:tool_name]}"
|
|
440
|
+
end
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Testing Your Migration
|
|
446
|
+
|
|
447
|
+
### 1. Check for Deprecated APIs
|
|
448
|
+
|
|
449
|
+
```ruby
|
|
450
|
+
# Run this in your test suite
|
|
451
|
+
describe "Migration compatibility" do
|
|
452
|
+
it "uses new Chat API" do
|
|
453
|
+
agent = swarm.agent(:backend)
|
|
454
|
+
|
|
455
|
+
# These should work
|
|
456
|
+
expect(agent).to respond_to(:has_tool?)
|
|
457
|
+
expect(agent).to respond_to(:tool_names)
|
|
458
|
+
expect(agent).to respond_to(:model_id)
|
|
459
|
+
|
|
460
|
+
# These are gone (don't test for them)
|
|
461
|
+
# agent.tools.key? - removed
|
|
462
|
+
# agent.model.id - removed
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it "uses new delegation names" do
|
|
466
|
+
expect(agent.has_tool?(:WorkWithDatabase)).to be true
|
|
467
|
+
expect(agent.has_tool?(:DelegateTaskToDatabase)).to be false
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### 2. Verify Workflow Separation
|
|
473
|
+
|
|
474
|
+
```ruby
|
|
475
|
+
describe "Workflow API" do
|
|
476
|
+
it "uses separate methods" do
|
|
477
|
+
# This should work
|
|
478
|
+
workflow = SwarmSDK.workflow do
|
|
479
|
+
node(:planning) { ... }
|
|
480
|
+
start_node :planning
|
|
481
|
+
end
|
|
482
|
+
expect(workflow).to be_a(SwarmSDK::Workflow)
|
|
483
|
+
|
|
484
|
+
# This should raise
|
|
485
|
+
expect {
|
|
486
|
+
SwarmSDK.build do
|
|
487
|
+
node(:planning) { ... } # ERROR!
|
|
488
|
+
end
|
|
489
|
+
}.to raise_error(SwarmSDK::ConfigurationError)
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### 3. Test Snapshot Compatibility
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
describe "Snapshot format" do
|
|
498
|
+
it "generates v2.1.0 snapshots" do
|
|
499
|
+
snapshot = swarm.snapshot
|
|
500
|
+
expect(snapshot.version).to eq("2.1.0")
|
|
501
|
+
expect(snapshot.data[:metadata]).to be_present
|
|
502
|
+
expect(snapshot.data[:swarm]).to be_nil # Old key removed
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Deprecation Timeline
|
|
510
|
+
|
|
511
|
+
- **v2.3.0** (This Release)
|
|
512
|
+
- Old APIs removed (no deprecation warnings)
|
|
513
|
+
- Migration required immediately
|
|
514
|
+
|
|
515
|
+
- **v2.4.0** (Future)
|
|
516
|
+
- No further breaking changes planned
|
|
517
|
+
- Focus on new features
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## Getting Help
|
|
522
|
+
|
|
523
|
+
If you encounter issues during migration:
|
|
524
|
+
|
|
525
|
+
1. **Check the CHANGELOG**: `docs/v2/CHANGELOG.swarm_sdk.md` has detailed explanations
|
|
526
|
+
2. **Run tests**: `bundle exec rake swarm_sdk:test` to catch compatibility issues
|
|
527
|
+
3. **Review examples**: `test/swarm_sdk/` contains comprehensive usage examples
|
|
528
|
+
4. **Report issues**: https://github.com/parruda/claude-swarm/issues
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Summary Checklist
|
|
533
|
+
|
|
534
|
+
- [ ] Update delegation tool calls: `DelegateTaskTo*` → `WorkWith*`
|
|
535
|
+
- [ ] Update delegation parameters: `task:` → `message:`
|
|
536
|
+
- [ ] Update Chat API usage: `tools.key?` → `has_tool?`, etc.
|
|
537
|
+
- [ ] Separate workflows: `SwarmSDK.build` → `SwarmSDK.workflow` for node-based configs
|
|
538
|
+
- [ ] Update YAML: `swarm:` key for swarms, `workflow:` key for workflows
|
|
539
|
+
- [ ] Regenerate snapshots (v1.0.0 → v2.1.0)
|
|
540
|
+
- [ ] Update custom plugins with new lifecycle methods
|
|
541
|
+
- [ ] Test all changes with `bundle exec rake swarm_sdk:test`
|
data/docs/v2/guides/snapshots.md
CHANGED
|
@@ -112,8 +112,8 @@ snapshot.write_to_file("session.json")
|
|
|
112
112
|
snapshot.write_to_file("session.json", pretty: false)
|
|
113
113
|
|
|
114
114
|
# Access metadata
|
|
115
|
-
snapshot.version
|
|
116
|
-
snapshot.type # => "swarm" or "
|
|
115
|
+
snapshot.version: 2.0.0"
|
|
116
|
+
snapshot.type # => "swarm" or "workflow"
|
|
117
117
|
snapshot.snapshot_at # => "2025-01-03T14:30:00Z"
|
|
118
118
|
snapshot.swarm_sdk_version # => "2.1.3"
|
|
119
119
|
snapshot.agent_names # => ["backend", "database"]
|
|
@@ -121,7 +121,7 @@ snapshot.delegation_instance_names # => ["database@backend"]
|
|
|
121
121
|
|
|
122
122
|
# Type checks
|
|
123
123
|
snapshot.swarm? # => true
|
|
124
|
-
snapshot.
|
|
124
|
+
snapshot.workflow? # => false
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
### Loading Snapshots
|
|
@@ -137,7 +137,7 @@ json_string = redis.get("session:#{user_id}")
|
|
|
137
137
|
snapshot = SwarmSDK::Snapshot.from_json(json_string)
|
|
138
138
|
|
|
139
139
|
# From hash
|
|
140
|
-
hash = { version:
|
|
140
|
+
hash = { version: 2.0.0", type: "swarm", ... }
|
|
141
141
|
snapshot = SwarmSDK::Snapshot.from_hash(hash)
|
|
142
142
|
```
|
|
143
143
|
|
|
@@ -616,7 +616,7 @@ result = swarm.restore(hash)
|
|
|
616
616
|
result = swarm.restore(json_string)
|
|
617
617
|
```
|
|
618
618
|
|
|
619
|
-
###
|
|
619
|
+
### Workflow Methods
|
|
620
620
|
|
|
621
621
|
Same API as Swarm:
|
|
622
622
|
|
|
@@ -639,8 +639,8 @@ Snapshot.from_json(json_string) # => Snapshot
|
|
|
639
639
|
Snapshot.from_hash(hash) # => Snapshot
|
|
640
640
|
|
|
641
641
|
# Metadata accessors
|
|
642
|
-
snapshot.version
|
|
643
|
-
snapshot.type # => "swarm" | "
|
|
642
|
+
snapshot.version: 2.0.0"
|
|
643
|
+
snapshot.type # => "swarm" | "workflow"
|
|
644
644
|
snapshot.snapshot_at # => "2025-01-03T14:30:00Z"
|
|
645
645
|
snapshot.swarm_sdk_version # => "2.1.3"
|
|
646
646
|
snapshot.agent_names # => ["agent1", "agent2"]
|
|
@@ -648,7 +648,7 @@ snapshot.delegation_instance_names # => ["agent2@agent1"]
|
|
|
648
648
|
|
|
649
649
|
# Type checks
|
|
650
650
|
snapshot.swarm? # => true | false
|
|
651
|
-
snapshot.
|
|
651
|
+
snapshot.workflow? # => true | false
|
|
652
652
|
```
|
|
653
653
|
|
|
654
654
|
### SnapshotFromEvents Class
|
|
@@ -799,10 +799,10 @@ swarm.restore(snapshot)
|
|
|
799
799
|
result = swarm.execute("Implement API endpoints using different pattern")
|
|
800
800
|
```
|
|
801
801
|
|
|
802
|
-
###
|
|
802
|
+
### Workflow Workflows
|
|
803
803
|
|
|
804
804
|
```ruby
|
|
805
|
-
orchestrator = SwarmSDK::
|
|
805
|
+
orchestrator = SwarmSDK::Workflow.new(
|
|
806
806
|
swarm_name: "Dev Workflow",
|
|
807
807
|
agent_definitions: { planner: planner_def, coder: coder_def },
|
|
808
808
|
nodes: { planning: planning_node, coding: coding_node },
|
|
@@ -819,7 +819,7 @@ snapshot.write_to_file("workflow_session.json")
|
|
|
819
819
|
# === Later, new process ===
|
|
820
820
|
|
|
821
821
|
# Restore and continue
|
|
822
|
-
orchestrator = SwarmSDK::
|
|
822
|
+
orchestrator = SwarmSDK::Workflow.new(...) # Same config
|
|
823
823
|
snapshot = SwarmSDK::Snapshot.from_file("workflow_session.json")
|
|
824
824
|
orchestrator.restore(snapshot)
|
|
825
825
|
|
|
@@ -1283,7 +1283,7 @@ swarm2.execute("Read scratchpad://tasks/auth.md")
|
|
|
1283
1283
|
# => Agent sees content from previous session
|
|
1284
1284
|
```
|
|
1285
1285
|
|
|
1286
|
-
**Note**:
|
|
1286
|
+
**Note**: Workflow doesn't snapshot scratchpad because each node creates its own fresh scratchpad.
|
|
1287
1287
|
|
|
1288
1288
|
## Troubleshooting
|
|
1289
1289
|
|
|
@@ -1340,9 +1340,9 @@ result = swarm.restore(snapshot)
|
|
|
1340
1340
|
|
|
1341
1341
|
### Type Mismatch
|
|
1342
1342
|
|
|
1343
|
-
**Problem**: `Snapshot type 'swarm' doesn't match orchestration type '
|
|
1343
|
+
**Problem**: `Snapshot type 'swarm' doesn't match orchestration type 'workflow'`
|
|
1344
1344
|
|
|
1345
|
-
**Cause**: Trying to restore swarm snapshot into
|
|
1345
|
+
**Cause**: Trying to restore swarm snapshot into Workflow (or vice versa)
|
|
1346
1346
|
|
|
1347
1347
|
**Solution**: Use correct orchestration type that matches snapshot
|
|
1348
1348
|
|
|
@@ -93,7 +93,7 @@ flowchart TB
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
subgraph "Node Workflows"
|
|
96
|
-
NODE_ORCH["
|
|
96
|
+
NODE_ORCH["Workflow<br/>(multi-stage execution)"]
|
|
97
97
|
NODE_CTX["NodeContext<br/>(goto_node, halt_workflow, skip_execution)"]
|
|
98
98
|
TRANSFORMERS["Bash/Ruby Transformers<br/>(input/output transformation)"]
|
|
99
99
|
MINI_SWARMS["Mini-Swarms<br/>(one per node)"]
|
|
@@ -318,7 +318,7 @@ Event occurs →
|
|
|
318
318
|
|
|
319
319
|
### 9. Node Workflow Flow
|
|
320
320
|
```
|
|
321
|
-
|
|
321
|
+
Workflow.execute →
|
|
322
322
|
Build execution order (topological sort) →
|
|
323
323
|
For each node:
|
|
324
324
|
Input transformer (Bash/Ruby) →
|
|
@@ -339,7 +339,7 @@ NodeOrchestrator.execute →
|
|
|
339
339
|
- **AgentInitializer**: Complex 5-pass initialization (tools, MCP, delegation, hooks)
|
|
340
340
|
- **ToolConfigurator**: Tool registration, creation, permissions wrapping
|
|
341
341
|
- **McpConfigurator**: MCP client management, external tool integration
|
|
342
|
-
- **
|
|
342
|
+
- **Workflow**: Multi-stage workflows with transformers
|
|
343
343
|
- **Plugin System**: Extensibility framework (SwarmMemory uses this)
|
|
344
344
|
|
|
345
345
|
### SwarmCLI
|
|
@@ -100,7 +100,7 @@ Emitted once per agent when agents are initialized (lazy initialization).
|
|
|
100
100
|
provider: "openai", # Provider name
|
|
101
101
|
directory: "./backend", # Working directory
|
|
102
102
|
system_prompt: "You are a backend dev...", # Full system prompt
|
|
103
|
-
tools: [:Read, :Edit, :Bash, :
|
|
103
|
+
tools: [:Read, :Edit, :Bash, :WorkWithFrontend], # Array of tool names
|
|
104
104
|
delegates_to: [:frontend], # Array of delegate agent names
|
|
105
105
|
plugin_storages: { # Plugin storage info (optional)
|
|
106
106
|
memory: {
|