claude_swarm 1.0.9 → 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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG.md → CHANGELOG.claude-swarm.md} +10 -0
  3. data/CLAUDE.md +346 -191
  4. data/decisions/2025-11-22-001-global-agent-registry.md +172 -0
  5. data/docs/v2/CHANGELOG.swarm_cli.md +20 -0
  6. data/docs/v2/CHANGELOG.swarm_memory.md +146 -1
  7. data/docs/v2/CHANGELOG.swarm_sdk.md +433 -10
  8. data/docs/v2/README.md +20 -5
  9. data/docs/v2/guides/complete-tutorial.md +95 -9
  10. data/docs/v2/guides/getting-started.md +10 -8
  11. data/docs/v2/guides/memory-adapters.md +41 -0
  12. data/docs/v2/guides/migrating-to-2.x.md +746 -0
  13. data/docs/v2/guides/plugins.md +52 -5
  14. data/docs/v2/guides/rails-integration.md +6 -0
  15. data/docs/v2/guides/snapshots.md +14 -14
  16. data/docs/v2/guides/swarm-memory.md +2 -13
  17. data/docs/v2/reference/architecture-flow.md +3 -3
  18. data/docs/v2/reference/cli.md +0 -1
  19. data/docs/v2/reference/configuration_reference.md +300 -0
  20. data/docs/v2/reference/event_payload_structures.md +27 -5
  21. data/docs/v2/reference/ruby-dsl.md +614 -18
  22. data/docs/v2/reference/swarm_memory_technical_details.md +7 -29
  23. data/docs/v2/reference/yaml.md +172 -54
  24. data/examples/snapshot_demo.rb +2 -2
  25. data/lib/claude_swarm/mcp_generator.rb +8 -21
  26. data/lib/claude_swarm/orchestrator.rb +8 -1
  27. data/lib/claude_swarm/version.rb +1 -1
  28. data/lib/swarm_cli/commands/run.rb +2 -2
  29. data/lib/swarm_cli/config_loader.rb +11 -11
  30. data/lib/swarm_cli/formatters/human_formatter.rb +0 -33
  31. data/lib/swarm_cli/interactive_repl.rb +2 -2
  32. data/lib/swarm_cli/ui/icons.rb +0 -23
  33. data/lib/swarm_cli/version.rb +1 -1
  34. data/lib/swarm_memory/adapters/filesystem_adapter.rb +11 -34
  35. data/lib/swarm_memory/core/semantic_index.rb +10 -2
  36. data/lib/swarm_memory/core/storage.rb +7 -2
  37. data/lib/swarm_memory/dsl/memory_config.rb +37 -0
  38. data/lib/swarm_memory/integration/sdk_plugin.rb +201 -28
  39. data/lib/swarm_memory/optimization/defragmenter.rb +1 -1
  40. data/lib/swarm_memory/prompts/memory_researcher.md.erb +0 -1
  41. data/lib/swarm_memory/tools/load_skill.rb +0 -1
  42. data/lib/swarm_memory/tools/memory_edit.rb +2 -1
  43. data/lib/swarm_memory/tools/memory_read.rb +1 -1
  44. data/lib/swarm_memory/version.rb +1 -1
  45. data/lib/swarm_memory.rb +8 -6
  46. data/lib/swarm_sdk/agent/builder.rb +58 -0
  47. data/lib/swarm_sdk/agent/chat.rb +527 -1061
  48. data/lib/swarm_sdk/agent/{chat → chat_helpers}/context_tracker.rb +13 -88
  49. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +204 -0
  50. data/lib/swarm_sdk/agent/{chat → chat_helpers}/hook_integration.rb +108 -46
  51. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +78 -0
  52. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +267 -0
  53. data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +3 -3
  54. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
  55. data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +11 -13
  56. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
  57. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +146 -0
  58. data/lib/swarm_sdk/agent/context.rb +1 -2
  59. data/lib/swarm_sdk/agent/definition.rb +66 -154
  60. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +4 -2
  61. data/lib/swarm_sdk/agent/system_prompt_builder.rb +161 -0
  62. data/lib/swarm_sdk/agent_registry.rb +146 -0
  63. data/lib/swarm_sdk/builders/base_builder.rb +488 -0
  64. data/lib/swarm_sdk/concerns/cleanupable.rb +39 -0
  65. data/lib/swarm_sdk/concerns/snapshotable.rb +67 -0
  66. data/lib/swarm_sdk/concerns/validatable.rb +55 -0
  67. data/lib/swarm_sdk/config.rb +302 -0
  68. data/lib/swarm_sdk/configuration/parser.rb +373 -0
  69. data/lib/swarm_sdk/configuration/translator.rb +255 -0
  70. data/lib/swarm_sdk/configuration.rb +77 -546
  71. data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
  72. data/lib/swarm_sdk/context_compactor.rb +6 -11
  73. data/lib/swarm_sdk/context_management/builder.rb +128 -0
  74. data/lib/swarm_sdk/context_management/context.rb +328 -0
  75. data/lib/swarm_sdk/custom_tool_registry.rb +226 -0
  76. data/lib/swarm_sdk/defaults.rb +196 -0
  77. data/lib/swarm_sdk/events_to_messages.rb +18 -0
  78. data/lib/swarm_sdk/hooks/adapter.rb +3 -3
  79. data/lib/swarm_sdk/hooks/shell_executor.rb +4 -2
  80. data/lib/swarm_sdk/log_collector.rb +179 -29
  81. data/lib/swarm_sdk/log_stream.rb +29 -0
  82. data/lib/swarm_sdk/models.json +4333 -1
  83. data/lib/swarm_sdk/models.rb +43 -2
  84. data/lib/swarm_sdk/node_context.rb +1 -1
  85. data/lib/swarm_sdk/observer/builder.rb +81 -0
  86. data/lib/swarm_sdk/observer/config.rb +45 -0
  87. data/lib/swarm_sdk/observer/manager.rb +236 -0
  88. data/lib/swarm_sdk/patterns/agent_observer.rb +160 -0
  89. data/lib/swarm_sdk/plugin.rb +95 -5
  90. data/lib/swarm_sdk/result.rb +52 -0
  91. data/lib/swarm_sdk/snapshot.rb +6 -6
  92. data/lib/swarm_sdk/snapshot_from_events.rb +13 -2
  93. data/lib/swarm_sdk/state_restorer.rb +136 -151
  94. data/lib/swarm_sdk/state_snapshot.rb +65 -100
  95. data/lib/swarm_sdk/swarm/agent_initializer.rb +181 -137
  96. data/lib/swarm_sdk/swarm/builder.rb +44 -578
  97. data/lib/swarm_sdk/swarm/executor.rb +213 -0
  98. data/lib/swarm_sdk/swarm/hook_triggers.rb +151 -0
  99. data/lib/swarm_sdk/swarm/logging_callbacks.rb +341 -0
  100. data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
  101. data/lib/swarm_sdk/swarm/tool_configurator.rb +58 -140
  102. data/lib/swarm_sdk/swarm.rb +203 -683
  103. data/lib/swarm_sdk/tools/bash.rb +14 -8
  104. data/lib/swarm_sdk/tools/delegate.rb +61 -43
  105. data/lib/swarm_sdk/tools/edit.rb +8 -13
  106. data/lib/swarm_sdk/tools/glob.rb +12 -4
  107. data/lib/swarm_sdk/tools/grep.rb +7 -0
  108. data/lib/swarm_sdk/tools/multi_edit.rb +15 -11
  109. data/lib/swarm_sdk/tools/path_resolver.rb +51 -2
  110. data/lib/swarm_sdk/tools/read.rb +16 -18
  111. data/lib/swarm_sdk/tools/registry.rb +122 -10
  112. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +9 -5
  113. data/lib/swarm_sdk/tools/stores/storage.rb +0 -6
  114. data/lib/swarm_sdk/tools/todo_write.rb +7 -0
  115. data/lib/swarm_sdk/tools/web_fetch.rb +20 -17
  116. data/lib/swarm_sdk/tools/write.rb +8 -13
  117. data/lib/swarm_sdk/version.rb +1 -1
  118. data/lib/swarm_sdk/{node → workflow}/agent_config.rb +1 -1
  119. data/lib/swarm_sdk/workflow/builder.rb +192 -0
  120. data/lib/swarm_sdk/workflow/executor.rb +497 -0
  121. data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +7 -5
  122. data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +5 -3
  123. data/lib/swarm_sdk/{node_orchestrator.rb → workflow.rb} +152 -456
  124. data/lib/swarm_sdk.rb +294 -108
  125. data/rubocop/cop/security/no_reflection_methods.rb +1 -1
  126. data/swarm_cli.gemspec +1 -1
  127. data/swarm_memory.gemspec +8 -3
  128. data/swarm_sdk.gemspec +6 -4
  129. data/team_full.yml +124 -320
  130. metadata +42 -14
  131. data/lib/swarm_memory/chat_extension.rb +0 -34
  132. data/lib/swarm_memory/tools/memory_multi_edit.rb +0 -281
  133. data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -589
  134. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -32,6 +32,242 @@ result = swarm.execute("Task prompt")
32
32
 
33
33
  ## Top-Level Methods
34
34
 
35
+ ### SwarmSDK.agent
36
+
37
+ Register an agent globally for reuse across multiple swarms.
38
+
39
+ **Signature:**
40
+ ```ruby
41
+ SwarmSDK.agent(name) {|builder| ... } → void
42
+ ```
43
+
44
+ **Parameters:**
45
+ - `name` (Symbol, required): Unique agent name
46
+ - `block` (required): Agent configuration block (uses [Agent Builder DSL](#agent-builder-dsl))
47
+
48
+ **Description:**
49
+ Registers an agent definition in a global registry, allowing it to be referenced by name in any swarm or workflow without re-defining it. This promotes code reuse and separation of concerns.
50
+
51
+ **Duplicate Registration:**
52
+ Raises `ArgumentError` if an agent with the same name is already registered. Use `SwarmSDK.clear_agent_registry!` to reset.
53
+
54
+ **Example - Define agents in separate files:**
55
+ ```ruby
56
+ # agents/backend.rb
57
+ SwarmSDK.agent :backend do
58
+ model "claude-sonnet-4"
59
+ description "Backend developer"
60
+ system_prompt "You build APIs and databases"
61
+ tools :Read, :Edit, :Bash
62
+ # Note: Don't set delegates_to here - it's swarm-specific!
63
+ end
64
+
65
+ # agents/database.rb
66
+ SwarmSDK.agent :database do
67
+ model "claude-sonnet-4"
68
+ description "Database specialist"
69
+ system_prompt "You design schemas and write migrations"
70
+ tools :Read, :Edit
71
+ end
72
+ ```
73
+
74
+ **Example - Reference in swarms:**
75
+ ```ruby
76
+ # Load agent definitions
77
+ require_relative "agents/backend"
78
+ require_relative "agents/database"
79
+
80
+ # Reference by name and configure delegation (swarm-specific)
81
+ swarm = SwarmSDK.build do
82
+ name "Dev Team"
83
+ lead :backend
84
+
85
+ agent :backend do
86
+ delegates_to :database # Delegation is swarm-specific
87
+ end
88
+ agent :database # Pulls from registry as-is
89
+ end
90
+ ```
91
+
92
+ **Example - Override registry settings:**
93
+ ```ruby
94
+ swarm = SwarmSDK.build do
95
+ name "Extended Team"
96
+ lead :backend
97
+
98
+ # Registry config applied first, then override block
99
+ agent :backend do
100
+ delegates_to :database, :cache # Set delegation for this swarm
101
+ tools :CustomTool # Adds to registry tools
102
+ timeout 300 # Overrides registry timeout
103
+ end
104
+ end
105
+ ```
106
+
107
+ **Workflow Auto-Resolution:**
108
+ Agents referenced in workflow nodes are automatically resolved from the registry if not defined at workflow level:
109
+
110
+ ```ruby
111
+ SwarmSDK.workflow do
112
+ name "Pipeline"
113
+ start_node :build
114
+
115
+ # No need to define :backend here - auto-resolved from registry!
116
+ node :build do
117
+ agent(:backend) # Resolved from global registry
118
+ end
119
+
120
+ node :test do
121
+ agent(:backend).delegates_to(:database) # Both resolved from registry
122
+ end
123
+ end
124
+ ```
125
+
126
+ **Use Cases:**
127
+ - **Code reuse**: Define agents once, use in multiple swarms
128
+ - **Separation of concerns**: Agent definitions in dedicated files
129
+ - **Testing**: Clear registry between tests with `SwarmSDK.clear_agent_registry!`
130
+ - **Organization**: Large projects with many agents
131
+
132
+ ---
133
+
134
+ ### SwarmSDK.clear_agent_registry!
135
+
136
+ Clear all registered agents from the global registry.
137
+
138
+ **Signature:**
139
+ ```ruby
140
+ SwarmSDK.clear_agent_registry! → void
141
+ ```
142
+
143
+ **Description:**
144
+ Removes all agents from the global registry. Primarily used for testing to ensure isolation between test cases.
145
+
146
+ **Example:**
147
+ ```ruby
148
+ # In test setup
149
+ def setup
150
+ SwarmSDK.clear_agent_registry!
151
+ end
152
+
153
+ # Or in RSpec
154
+ before(:each) do
155
+ SwarmSDK.clear_agent_registry!
156
+ end
157
+ ```
158
+
159
+ ---
160
+
161
+ ### SwarmSDK.build
162
+
163
+ Build a simple multi-agent swarm.
164
+
165
+ **Signature:**
166
+ ```ruby
167
+ SwarmSDK.build(allow_filesystem_tools: nil) {|builder| ... } → Swarm
168
+ ```
169
+
170
+ **Returns:**
171
+ - `Swarm` - Always returns a Swarm instance (simple multi-agent collaboration)
172
+
173
+ **Parameters:**
174
+ - `allow_filesystem_tools` (Boolean, optional): Override global filesystem tools setting for this swarm
175
+ - `block` (required): Configuration block using the DSL
176
+
177
+ **Description:**
178
+ Creates a simple multi-agent swarm where agents can collaborate through delegation. Use this for most use cases where you need multiple AI agents working together.
179
+
180
+ **Example:**
181
+ ```ruby
182
+ swarm = SwarmSDK.build do
183
+ name "Development Team"
184
+ lead :backend
185
+
186
+ agent :backend do
187
+ model "gpt-4"
188
+ description "Backend developer"
189
+ tools :Read, :Write, :Bash
190
+ delegates_to :tester
191
+ end
192
+
193
+ agent :tester do
194
+ model "gpt-4o-mini"
195
+ description "Test specialist"
196
+ tools :Read, :Bash
197
+ end
198
+ end
199
+
200
+ result = swarm.execute("Build authentication API")
201
+ ```
202
+
203
+ **Notes:**
204
+ - Cannot use `node` definitions (raises `ConfigurationError`)
205
+ - Must specify `lead` agent
206
+ - For multi-stage workflows, use `SwarmSDK.workflow` instead
207
+
208
+ ---
209
+
210
+ ### SwarmSDK.workflow
211
+
212
+ Build a multi-stage workflow with nodes.
213
+
214
+ **Signature:**
215
+ ```ruby
216
+ SwarmSDK.workflow(allow_filesystem_tools: nil) {|builder| ... } → Workflow
217
+ ```
218
+
219
+ **Returns:**
220
+ - `Workflow` - Always returns a Workflow instance (multi-stage pipeline)
221
+
222
+ **Parameters:**
223
+ - `allow_filesystem_tools` (Boolean, optional): Override global filesystem tools setting for this workflow
224
+ - `block` (required): Configuration block using the DSL
225
+
226
+ **Description:**
227
+ Creates a multi-stage workflow where different teams of agents execute in sequence. Each node is an independent swarm execution with its own agent configuration and delegation topology. Use this for complex pipelines with distinct stages (planning → implementation → testing).
228
+
229
+ **Example:**
230
+ ```ruby
231
+ workflow = SwarmSDK.workflow do
232
+ name "Build Pipeline"
233
+ start_node :planning
234
+
235
+ agent :architect do
236
+ model "gpt-4"
237
+ description "System architect"
238
+ end
239
+
240
+ agent :coder do
241
+ model "gpt-4"
242
+ description "Implementation specialist"
243
+ end
244
+
245
+ node :planning do
246
+ agent(:architect)
247
+ end
248
+
249
+ node :implementation do
250
+ agent(:coder)
251
+ depends_on :planning
252
+
253
+ # Transform input from planning node
254
+ input do |ctx|
255
+ "Implement this plan:\n#{ctx.content}"
256
+ end
257
+ end
258
+ end
259
+
260
+ result = workflow.execute("Build authentication system")
261
+ ```
262
+
263
+ **Notes:**
264
+ - Cannot use `lead` (raises `ConfigurationError`)
265
+ - Must specify `start_node`
266
+ - Nodes execute in topological order based on `depends_on`
267
+ - Each node can have different agents and delegation topology
268
+
269
+ ---
270
+
35
271
  ### SwarmSDK.configure
36
272
 
37
273
  Configure global SwarmSDK settings.
@@ -51,6 +287,8 @@ SwarmSDK.configure {|config| ... } → void
51
287
  - `webfetch_max_tokens` (Integer): Maximum tokens for WebFetch LLM responses (default: 4096)
52
288
  - `allow_filesystem_tools` (Boolean): Enable/disable filesystem tools globally (default: true)
53
289
 
290
+ **See [Configuration Reference](configuration_reference.md) for the complete list of 45+ configuration options including API keys, timeouts, limits, and more.**
291
+
54
292
  **Description:**
55
293
  Global configuration that applies to all swarms.
56
294
 
@@ -88,13 +326,220 @@ SwarmSDK.configure do |config|
88
326
  end
89
327
 
90
328
  # Can also set directly
91
- SwarmSDK.settings.allow_filesystem_tools = false
329
+ SwarmSDK.config.allow_filesystem_tools = false
92
330
 
93
331
  # Or via environment variable
94
332
  ENV['SWARM_SDK_ALLOW_FILESYSTEM_TOOLS'] = 'false'
95
333
 
96
334
  # Reset to defaults (disables WebFetch LLM processing, enables filesystem tools)
97
- SwarmSDK.reset_settings!
335
+ SwarmSDK.reset_config!
336
+ ```
337
+
338
+ ---
339
+
340
+ ### Custom Tool Registration
341
+
342
+ Simple API for registering custom tools without creating full plugins.
343
+
344
+ #### SwarmSDK.register_tool
345
+
346
+ Register a custom RubyLLM::Tool for use in swarms.
347
+
348
+ **Signatures:**
349
+ ```ruby
350
+ SwarmSDK.register_tool(tool_class) → Symbol
351
+ SwarmSDK.register_tool(name, tool_class) → Symbol
352
+ ```
353
+
354
+ **Parameters:**
355
+ - `tool_class` (Class): RubyLLM::Tool subclass to register
356
+ - `name` (Symbol, optional): Explicit tool name (if not provided, name is inferred)
357
+
358
+ **Returns:**
359
+ - `Symbol`: The registered tool name
360
+
361
+ **Description:**
362
+ Registers a custom tool globally so it can be used in any swarm. Tools are registered by name and can be referenced in agent configurations.
363
+
364
+ **Tool Lookup Order:**
365
+ 1. Plugin tools (from PluginRegistry)
366
+ 2. Custom tools (from CustomToolRegistry)
367
+ 3. Built-in tools (from Tools::Registry)
368
+
369
+ **Name Inference:**
370
+ If no name is provided, the tool name is inferred from the class name by:
371
+ 1. Taking the last component (e.g., `MyApp::Tools::WeatherTool` → `WeatherTool`)
372
+ 2. Removing the `Tool` suffix if present (e.g., `WeatherTool` → `Weather`)
373
+
374
+ **Context Support:**
375
+ Tools can declare `creation_requirements` to receive agent context:
376
+ - `:agent_name` - Agent identifier (Symbol)
377
+ - `:directory` - Agent's working directory (String)
378
+
379
+ **Validation:**
380
+ - Tool class must inherit from `RubyLLM::Tool`
381
+ - Cannot override built-in tools (Read, Write, Edit, etc.)
382
+ - Cannot override plugin tools (MemoryWrite, etc.)
383
+ - Cannot register the same name twice
384
+
385
+ **When to Use:**
386
+ - Simple, stateless tools
387
+ - No persistent storage needed
388
+ - No lifecycle hooks required
389
+ - Quick setup without plugin infrastructure
390
+
391
+ **When to Use Plugins Instead:**
392
+ - Need per-agent storage
393
+ - Need lifecycle hooks (on_agent_initialized, on_user_message, etc.)
394
+ - Want to contribute to system prompts
395
+ - Building suite of related tools
396
+
397
+ **Example - Simple Tool:**
398
+ ```ruby
399
+ class WeatherTool < RubyLLM::Tool
400
+ description "Get weather for a city"
401
+ param :city, type: "string", required: true
402
+
403
+ def execute(city:)
404
+ # Call weather API
405
+ "Weather in #{city}: Sunny, 72°F"
406
+ end
407
+ end
408
+
409
+ # Register with inferred name (:Weather)
410
+ SwarmSDK.register_tool(WeatherTool)
411
+
412
+ # Use in swarm
413
+ SwarmSDK.build do
414
+ agent :assistant do
415
+ model "claude-sonnet-4"
416
+ tools :Weather, :Read # Mix custom and built-in tools
417
+ end
418
+ end
419
+ ```
420
+
421
+ **Example - Context-Aware Tool:**
422
+ ```ruby
423
+ class AgentLogTool < RubyLLM::Tool
424
+ # Declare required context
425
+ def self.creation_requirements
426
+ [:agent_name, :directory]
427
+ end
428
+
429
+ description "Log a message for this agent"
430
+ param :message, type: "string", required: true
431
+
432
+ def initialize(agent_name:, directory:)
433
+ super()
434
+ @agent_name = agent_name
435
+ @log_file = File.join(directory, ".agent.log")
436
+ end
437
+
438
+ def execute(message:)
439
+ File.append(@log_file, "[#{@agent_name}] #{message}\n")
440
+ "Logged message to #{@log_file}"
441
+ end
442
+ end
443
+
444
+ SwarmSDK.register_tool(:AgentLog, AgentLogTool)
445
+ ```
446
+
447
+ **Example - Explicit Name:**
448
+ ```ruby
449
+ # Register with custom name
450
+ SwarmSDK.register_tool(:GetWeather, WeatherTool)
451
+
452
+ SwarmSDK.build do
453
+ agent :assistant do
454
+ tools :GetWeather # Use the custom name
455
+ end
456
+ end
457
+ ```
458
+
459
+ #### SwarmSDK.custom_tool_registered?
460
+
461
+ Check if a custom tool is registered.
462
+
463
+ **Signature:**
464
+ ```ruby
465
+ SwarmSDK.custom_tool_registered?(name) → Boolean
466
+ ```
467
+
468
+ **Parameters:**
469
+ - `name` (Symbol | String): Tool name to check
470
+
471
+ **Returns:**
472
+ - `true` if tool is registered, `false` otherwise
473
+
474
+ **Example:**
475
+ ```ruby
476
+ SwarmSDK.register_tool(WeatherTool)
477
+ SwarmSDK.custom_tool_registered?(:Weather) # => true
478
+ SwarmSDK.custom_tool_registered?("Weather") # => true
479
+ SwarmSDK.custom_tool_registered?(:Unknown) # => false
480
+ ```
481
+
482
+ #### SwarmSDK.custom_tools
483
+
484
+ List all registered custom tool names.
485
+
486
+ **Signature:**
487
+ ```ruby
488
+ SwarmSDK.custom_tools → Array<Symbol>
489
+ ```
490
+
491
+ **Returns:**
492
+ - Array of registered tool names (as symbols)
493
+
494
+ **Example:**
495
+ ```ruby
496
+ SwarmSDK.register_tool(WeatherTool)
497
+ SwarmSDK.register_tool(:Stock, StockPriceTool)
498
+
499
+ SwarmSDK.custom_tools # => [:Weather, :Stock]
500
+ ```
501
+
502
+ #### SwarmSDK.unregister_tool
503
+
504
+ Remove a registered custom tool.
505
+
506
+ **Signature:**
507
+ ```ruby
508
+ SwarmSDK.unregister_tool(name) → Class | nil
509
+ ```
510
+
511
+ **Parameters:**
512
+ - `name` (Symbol | String): Tool name to unregister
513
+
514
+ **Returns:**
515
+ - The unregistered tool class, or `nil` if not found
516
+
517
+ **Example:**
518
+ ```ruby
519
+ removed = SwarmSDK.unregister_tool(:Weather)
520
+ removed # => WeatherTool
521
+ ```
522
+
523
+ #### SwarmSDK.clear_custom_tools!
524
+
525
+ Clear all registered custom tools.
526
+
527
+ **Signature:**
528
+ ```ruby
529
+ SwarmSDK.clear_custom_tools! → void
530
+ ```
531
+
532
+ **Description:**
533
+ Removes all custom tool registrations. Primarily useful for testing to ensure clean state between test runs.
534
+
535
+ **Example:**
536
+ ```ruby
537
+ SwarmSDK.register_tool(WeatherTool)
538
+ SwarmSDK.register_tool(StockPriceTool)
539
+
540
+ SwarmSDK.clear_custom_tools!
541
+
542
+ SwarmSDK.custom_tools # => []
98
543
  ```
99
544
 
100
545
  ---
@@ -105,7 +550,7 @@ Build a swarm using the DSL.
105
550
 
106
551
  **Signature:**
107
552
  ```ruby
108
- SwarmSDK.build(allow_filesystem_tools: nil, &block) → Swarm | NodeOrchestrator
553
+ SwarmSDK.build(allow_filesystem_tools: nil, &block) → Swarm | Workflow
109
554
  ```
110
555
 
111
556
  **Parameters:**
@@ -114,7 +559,7 @@ SwarmSDK.build(allow_filesystem_tools: nil, &block) → Swarm | NodeOrchestrator
114
559
 
115
560
  **Returns:**
116
561
  - `Swarm`: For single-swarm configurations
117
- - `NodeOrchestrator`: For multi-node workflow configurations
562
+ - `Workflow`: For multi-node workflow configurations
118
563
 
119
564
  **Example:**
120
565
  ```ruby
@@ -400,7 +845,7 @@ scratchpad(mode) → void
400
845
  **Parameters:**
401
846
  - `mode` (Symbol, required): Scratchpad mode
402
847
  - For regular Swarms: `:enabled` or `:disabled`
403
- - For NodeOrchestrator (workflows with nodes): `:enabled`, `:per_node`, or `:disabled`
848
+ - For Workflow (workflows with nodes): `:enabled`, `:per_node`, or `:disabled`
404
849
 
405
850
  **Default:** `:disabled`
406
851
 
@@ -409,8 +854,8 @@ Controls scratchpad availability and sharing behavior:
409
854
 
410
855
  - **`:enabled`**: Scratchpad tools available (ScratchpadWrite, ScratchpadRead, ScratchpadList)
411
856
  - Regular Swarm: All agents share one scratchpad
412
- - NodeOrchestrator: All nodes share one scratchpad across the workflow
413
- - **`:per_node`**: (NodeOrchestrator only) Each node gets isolated scratchpad storage
857
+ - Workflow: All nodes share one scratchpad across the workflow
858
+ - **`:per_node`**: (Workflow only) Each node gets isolated scratchpad storage
414
859
  - **`:disabled`**: No scratchpad tools available
415
860
 
416
861
  Scratchpad is volatile (in-memory only) and provides temporary storage for cross-agent or cross-node communication.
@@ -423,7 +868,7 @@ SwarmSDK.build do
423
868
  scratchpad :disabled # Disable scratchpad (default)
424
869
  end
425
870
 
426
- # NodeOrchestrator - shared across nodes
871
+ # Workflow - shared across nodes
427
872
  SwarmSDK.build do
428
873
  scratchpad :enabled # All nodes share one scratchpad
429
874
 
@@ -432,7 +877,7 @@ SwarmSDK.build do
432
877
  start_node :planning
433
878
  end
434
879
 
435
- # NodeOrchestrator - isolated per node
880
+ # Workflow - isolated per node
436
881
  SwarmSDK.build do
437
882
  scratchpad :per_node # Each node gets its own scratchpad
438
883
 
@@ -870,7 +1315,7 @@ tools(*tool_names, include_default: true) → void
870
1315
  - `ScratchpadWrite`, `ScratchpadRead`, `ScratchpadList`
871
1316
 
872
1317
  **Memory tools** (added if agent has `memory` configured):
873
- - `MemoryWrite`, `MemoryRead`, `MemoryEdit`, `MemoryMultiEdit`, `MemoryGlob`, `MemoryGrep`, `MemoryDelete`
1318
+ - `MemoryWrite`, `MemoryRead`, `MemoryEdit`, `MemoryGlob`, `MemoryGrep`, `MemoryDelete`
874
1319
 
875
1320
  **Additional tools:**
876
1321
  - `Write`, `Edit`, `MultiEdit`, `Bash`
@@ -910,7 +1355,7 @@ delegates_to(*agent_names) → void
910
1355
 
911
1356
  **Behavior:**
912
1357
  - Multiple calls are cumulative
913
- - Creates a `DelegateTaskTo{Agent}` tool for each target (e.g., `DelegateTaskToDatabase`)
1358
+ - Creates a `WorkWith{Agent}` tool for each target (e.g., `WorkWithDatabase`)
914
1359
 
915
1360
  **Example:**
916
1361
  ```ruby
@@ -1019,7 +1464,7 @@ memory(&block) → void
1019
1464
  - `directory(string)` - Directory where memory.json will be stored (required)
1020
1465
 
1021
1466
  **Description:**
1022
- Enables persistent memory for the agent. When configured, the agent automatically gets all 7 memory tools (MemoryWrite, MemoryRead, MemoryEdit, MemoryMultiEdit, MemoryGlob, MemoryGrep, MemoryDelete) and a memory system prompt is appended to help the agent use memory effectively.
1467
+ Enables persistent memory for the agent. When configured, the agent automatically gets all 6 memory tools (MemoryWrite, MemoryRead, MemoryEdit, MemoryGlob, MemoryGrep, MemoryDelete) and a memory system prompt is appended to help the agent use memory effectively.
1023
1468
 
1024
1469
  Memory is per-agent (isolated) and persistent (survives across sessions).
1025
1470
 
@@ -1962,16 +2407,19 @@ Execute a task using the lead agent.
1962
2407
 
1963
2408
  **Signature:**
1964
2409
  ```ruby
1965
- swarm.execute(prompt, &block) → Result
2410
+ swarm.execute(prompt, wait: true, &block) → Result | Async::Task
1966
2411
  ```
1967
2412
 
1968
2413
  **Parameters:**
1969
2414
  - `prompt` (String, required): Task prompt
2415
+ - `wait` (Boolean, optional): If true (default), blocks until execution completes. If false, returns Async::Task immediately for non-blocking execution.
1970
2416
  - `block` (optional): Log entry handler for streaming
1971
2417
 
1972
- **Returns:** `Result` object
2418
+ **Returns:**
2419
+ - `Result` if `wait: true` (default)
2420
+ - `Async::Task` if `wait: false`
1973
2421
 
1974
- **Example:**
2422
+ **Example - Blocking execution (default):**
1975
2423
  ```ruby
1976
2424
  # Basic execution
1977
2425
  result = swarm.execute("Build a REST API")
@@ -1992,6 +2440,36 @@ else
1992
2440
  end
1993
2441
  ```
1994
2442
 
2443
+ **Example - Non-blocking execution with cancellation:**
2444
+ ```ruby
2445
+ # Start non-blocking execution
2446
+ task = swarm.execute("Build a REST API", wait: false) do |log_entry|
2447
+ puts "#{log_entry[:type]}: #{log_entry[:agent]}"
2448
+ end
2449
+
2450
+ # ... do other work ...
2451
+
2452
+ # Cancel anytime
2453
+ task.stop
2454
+
2455
+ # Wait for result (returns nil if cancelled)
2456
+ result = task.wait
2457
+ if result.nil?
2458
+ puts "Execution was cancelled"
2459
+ elsif result.success?
2460
+ puts result.content
2461
+ else
2462
+ puts "Error: #{result.error.message}"
2463
+ end
2464
+ ```
2465
+
2466
+ **Non-blocking execution details:**
2467
+ - **`wait: false`**: Returns `Async::Task` immediately, enabling cancellation via `task.stop`
2468
+ - **Cooperative cancellation**: Stops when fiber yields (HTTP I/O, tool boundaries), not immediate
2469
+ - **Proper cleanup**: MCP clients, fiber storage, and logging cleaned in task's ensure block
2470
+ - **`task.wait` returns nil**: Cancelled tasks return `nil` from `wait` method
2471
+ - **Use cases**: Long-running tasks, user-initiated cancellation, timeout handling
2472
+
1995
2473
  ---
1996
2474
 
1997
2475
  ## Result Object
@@ -2088,6 +2566,124 @@ result.to_json → String
2088
2566
  ```
2089
2567
  Convert to JSON string.
2090
2568
 
2569
+ **per_agent_usage**
2570
+ ```ruby
2571
+ result.per_agent_usage → Hash<Symbol, Hash>
2572
+ ```
2573
+ Returns per-agent usage breakdown extracted from execution logs.
2574
+
2575
+ Each agent entry contains:
2576
+ - `input_tokens` - Input tokens for this agent
2577
+ - `output_tokens` - Output tokens for this agent
2578
+ - `total_tokens` - Total tokens (input + output)
2579
+ - `cached_tokens` - Cached tokens used
2580
+ - `context_limit` - Context window limit
2581
+ - `usage_percentage` - Percentage of context window used
2582
+ - `tokens_remaining` - Tokens remaining in context window
2583
+ - `input_cost` - Input cost in dollars
2584
+ - `output_cost` - Output cost in dollars
2585
+ - `total_cost` - Total cost in dollars
2586
+
2587
+ **Example:**
2588
+ ```ruby
2589
+ result = swarm.execute("Build authentication")
2590
+ usage = result.per_agent_usage
2591
+
2592
+ usage[:backend]
2593
+ # => {
2594
+ # input_tokens: 15000,
2595
+ # output_tokens: 5000,
2596
+ # total_tokens: 20000,
2597
+ # cached_tokens: 2000,
2598
+ # context_limit: 200000,
2599
+ # usage_percentage: 10.0,
2600
+ # tokens_remaining: 180000,
2601
+ # input_cost: 0.045,
2602
+ # output_cost: 0.075,
2603
+ # total_cost: 0.12
2604
+ # }
2605
+ ```
2606
+
2607
+ ---
2608
+
2609
+ ## Swarm Methods
2610
+
2611
+ ### context_breakdown
2612
+
2613
+ Get real-time context usage breakdown for all agents.
2614
+
2615
+ **Signature:**
2616
+ ```ruby
2617
+ swarm.context_breakdown → Hash<Symbol, Hash>
2618
+ ```
2619
+
2620
+ **Returns:**
2621
+ Hash with agent names as keys and context usage info as values.
2622
+
2623
+ **Description:**
2624
+ Returns live context metrics for all agents in the swarm, including both primary agents and delegation instances. Useful for monitoring token consumption and costs during execution.
2625
+
2626
+ Each agent entry contains:
2627
+ - `input_tokens` - Cumulative input tokens
2628
+ - `output_tokens` - Cumulative output tokens
2629
+ - `total_tokens` - Total tokens (input + output)
2630
+ - `cached_tokens` - Cached tokens used
2631
+ - `cache_creation_tokens` - Tokens written to cache
2632
+ - `effective_input_tokens` - Actual input tokens charged (input - cached)
2633
+ - `context_limit` - Context window limit for the model
2634
+ - `usage_percentage` - Percentage of context window used
2635
+ - `tokens_remaining` - Tokens remaining in context window
2636
+ - `input_cost` - Cumulative input cost in dollars
2637
+ - `output_cost` - Cumulative output cost in dollars
2638
+ - `total_cost` - Cumulative total cost in dollars
2639
+
2640
+ **Example:**
2641
+ ```ruby
2642
+ swarm = SwarmSDK.build do
2643
+ name "Dev Team"
2644
+ lead :backend
2645
+
2646
+ agent :backend do
2647
+ model "claude-sonnet-4"
2648
+ delegates_to :tester
2649
+ end
2650
+
2651
+ agent :tester do
2652
+ model "gpt-4o-mini"
2653
+ end
2654
+ end
2655
+
2656
+ # During or after execution
2657
+ breakdown = swarm.context_breakdown
2658
+
2659
+ # Primary agent
2660
+ breakdown[:backend]
2661
+ # => {
2662
+ # input_tokens: 15000,
2663
+ # output_tokens: 5000,
2664
+ # total_tokens: 20000,
2665
+ # cached_tokens: 2000,
2666
+ # cache_creation_tokens: 1000,
2667
+ # effective_input_tokens: 13000,
2668
+ # context_limit: 200000,
2669
+ # usage_percentage: 10.0,
2670
+ # tokens_remaining: 180000,
2671
+ # input_cost: 0.045,
2672
+ # output_cost: 0.075,
2673
+ # total_cost: 0.12
2674
+ # }
2675
+
2676
+ # Delegation instance
2677
+ breakdown[:"tester@backend"]
2678
+ # => { ... same structure ... }
2679
+ ```
2680
+
2681
+ **Use Cases:**
2682
+ - Monitor token consumption during long-running tasks
2683
+ - Track costs per agent in real-time
2684
+ - Identify context-heavy agents approaching limits
2685
+ - Debug context window issues
2686
+
2091
2687
  ---
2092
2688
 
2093
2689
  ## Context Management
@@ -2421,7 +3017,7 @@ Jump to a different node with custom content, bypassing normal dependency order.
2421
3017
  - `node_name` (Symbol, required): Target node name
2422
3018
  - `content` (String, required): Content to pass to target node (validated non-nil)
2423
3019
 
2424
- **Returns:** Control hash (processed by NodeOrchestrator)
3020
+ **Returns:** Control hash (processed by Workflow)
2425
3021
 
2426
3022
  **Valid in:** Both input and output transformers
2427
3023
 
@@ -2452,7 +3048,7 @@ Stop entire workflow execution immediately and return content as final result.
2452
3048
  **Parameters:**
2453
3049
  - `content` (String, required): Final content to return (validated non-nil)
2454
3050
 
2455
- **Returns:** Control hash (processed by NodeOrchestrator)
3051
+ **Returns:** Control hash (processed by Workflow)
2456
3052
 
2457
3053
  **Valid in:** Both input and output transformers
2458
3054
 
@@ -2483,7 +3079,7 @@ Skip LLM execution for current node and use provided content instead.
2483
3079
  **Parameters:**
2484
3080
  - `content` (String, required): Content to use instead of LLM execution (validated non-nil)
2485
3081
 
2486
- **Returns:** Control hash (processed by NodeOrchestrator)
3082
+ **Returns:** Control hash (processed by Workflow)
2487
3083
 
2488
3084
  **Valid in:** Input transformers only
2489
3085