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.
- checksums.yaml +4 -4
- data/{CHANGELOG.md → CHANGELOG.claude-swarm.md} +10 -0
- data/CLAUDE.md +346 -191
- data/decisions/2025-11-22-001-global-agent-registry.md +172 -0
- data/docs/v2/CHANGELOG.swarm_cli.md +20 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +146 -1
- data/docs/v2/CHANGELOG.swarm_sdk.md +433 -10
- data/docs/v2/README.md +20 -5
- data/docs/v2/guides/complete-tutorial.md +95 -9
- data/docs/v2/guides/getting-started.md +10 -8
- data/docs/v2/guides/memory-adapters.md +41 -0
- data/docs/v2/guides/migrating-to-2.x.md +746 -0
- data/docs/v2/guides/plugins.md +52 -5
- data/docs/v2/guides/rails-integration.md +6 -0
- data/docs/v2/guides/snapshots.md +14 -14
- data/docs/v2/guides/swarm-memory.md +2 -13
- data/docs/v2/reference/architecture-flow.md +3 -3
- data/docs/v2/reference/cli.md +0 -1
- data/docs/v2/reference/configuration_reference.md +300 -0
- data/docs/v2/reference/event_payload_structures.md +27 -5
- data/docs/v2/reference/ruby-dsl.md +614 -18
- data/docs/v2/reference/swarm_memory_technical_details.md +7 -29
- data/docs/v2/reference/yaml.md +172 -54
- data/examples/snapshot_demo.rb +2 -2
- data/lib/claude_swarm/mcp_generator.rb +8 -21
- data/lib/claude_swarm/orchestrator.rb +8 -1
- 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/core/semantic_index.rb +10 -2
- data/lib/swarm_memory/core/storage.rb +7 -2
- data/lib/swarm_memory/dsl/memory_config.rb +37 -0
- data/lib/swarm_memory/integration/sdk_plugin.rb +201 -28
- data/lib/swarm_memory/optimization/defragmenter.rb +1 -1
- data/lib/swarm_memory/prompts/memory_researcher.md.erb +0 -1
- data/lib/swarm_memory/tools/load_skill.rb +0 -1
- data/lib/swarm_memory/tools/memory_edit.rb +2 -1
- data/lib/swarm_memory/tools/memory_read.rb +1 -1
- data/lib/swarm_memory/version.rb +1 -1
- data/lib/swarm_memory.rb +8 -6
- 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 +13 -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 +267 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/logging_helpers.rb +3 -3
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +83 -0
- data/lib/swarm_sdk/agent/{chat → chat_helpers}/system_reminder_injector.rb +11 -13
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +79 -0
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +146 -0
- data/lib/swarm_sdk/agent/context.rb +1 -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/agent_registry.rb +146 -0
- data/lib/swarm_sdk/builders/base_builder.rb +488 -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/config.rb +302 -0
- data/lib/swarm_sdk/configuration/parser.rb +373 -0
- data/lib/swarm_sdk/configuration/translator.rb +255 -0
- data/lib/swarm_sdk/configuration.rb +77 -546
- data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
- 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/custom_tool_registry.rb +226 -0
- data/lib/swarm_sdk/defaults.rb +196 -0
- data/lib/swarm_sdk/events_to_messages.rb +18 -0
- data/lib/swarm_sdk/hooks/adapter.rb +3 -3
- data/lib/swarm_sdk/hooks/shell_executor.rb +4 -2
- data/lib/swarm_sdk/log_collector.rb +179 -29
- data/lib/swarm_sdk/log_stream.rb +29 -0
- data/lib/swarm_sdk/models.json +4333 -1
- data/lib/swarm_sdk/models.rb +43 -2
- 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 +95 -5
- data/lib/swarm_sdk/result.rb +52 -0
- 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 +181 -137
- 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 +151 -0
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +341 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +7 -4
- data/lib/swarm_sdk/swarm/tool_configurator.rb +58 -140
- data/lib/swarm_sdk/swarm.rb +203 -683
- data/lib/swarm_sdk/tools/bash.rb +14 -8
- 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 +12 -4
- 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 +16 -18
- data/lib/swarm_sdk/tools/registry.rb +122 -10
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +9 -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 +20 -17
- 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 +192 -0
- data/lib/swarm_sdk/workflow/executor.rb +497 -0
- data/lib/swarm_sdk/{node/builder.rb → workflow/node_builder.rb} +7 -5
- data/lib/swarm_sdk/{node → workflow}/transformer_executor.rb +5 -3
- data/lib/swarm_sdk/{node_orchestrator.rb → workflow.rb} +152 -456
- data/lib/swarm_sdk.rb +294 -108
- data/rubocop/cop/security/no_reflection_methods.rb +1 -1
- data/swarm_cli.gemspec +1 -1
- data/swarm_memory.gemspec +8 -3
- data/swarm_sdk.gemspec +6 -4
- data/team_full.yml +124 -320
- metadata +42 -14
- data/lib/swarm_memory/chat_extension.rb +0 -34
- data/lib/swarm_memory/tools/memory_multi_edit.rb +0 -281
- data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -589
- /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.
|
|
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.
|
|
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 |
|
|
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
|
-
- `
|
|
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
|
|
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
|
-
-
|
|
413
|
-
- **`:per_node`**: (
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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`, `
|
|
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 `
|
|
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
|
|
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:**
|
|
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
|
|
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
|
|
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
|
|
3082
|
+
**Returns:** Control hash (processed by Workflow)
|
|
2487
3083
|
|
|
2488
3084
|
**Valid in:** Input transformers only
|
|
2489
3085
|
|