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
data/lib/swarm_sdk/plugin.rb
CHANGED
|
@@ -10,7 +10,7 @@ module SwarmSDK
|
|
|
10
10
|
# ## Adding Custom Attributes to Agents
|
|
11
11
|
#
|
|
12
12
|
# Plugins can add custom attributes to Agent::Definition that are preserved
|
|
13
|
-
# when agents are cloned (e.g., in
|
|
13
|
+
# when agents are cloned (e.g., in Workflow). To do this:
|
|
14
14
|
#
|
|
15
15
|
# 1. Add attr_reader to Agent::Definition for your attribute
|
|
16
16
|
# 2. Parse the attribute in Agent::Definition#initialize
|
|
@@ -62,7 +62,7 @@ module SwarmSDK
|
|
|
62
62
|
# my_custom_config { option: "value" }
|
|
63
63
|
# end
|
|
64
64
|
#
|
|
65
|
-
# And it will be preserved when
|
|
65
|
+
# And it will be preserved when Workflow clones the agent!
|
|
66
66
|
#
|
|
67
67
|
# @example Real-world: SwarmMemory plugin
|
|
68
68
|
# # SwarmMemory adds 'memory' attribute to agents
|
|
@@ -139,11 +139,11 @@ module SwarmSDK
|
|
|
139
139
|
[]
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
#
|
|
142
|
+
# Check if memory is configured for this agent (optional)
|
|
143
143
|
#
|
|
144
144
|
# @param agent_definition [Agent::Definition] Agent definition
|
|
145
145
|
# @return [Boolean] True if storage should be created
|
|
146
|
-
def
|
|
146
|
+
def memory_configured?(agent_definition)
|
|
147
147
|
false
|
|
148
148
|
end
|
|
149
149
|
|
|
@@ -197,7 +197,7 @@ module SwarmSDK
|
|
|
197
197
|
# Contribute to agent serialization (optional)
|
|
198
198
|
#
|
|
199
199
|
# Called when Agent::Definition.to_h is invoked (e.g., for cloning agents
|
|
200
|
-
# in
|
|
200
|
+
# in Workflow). Plugins can return config keys that should be
|
|
201
201
|
# included in the serialized hash to preserve their state.
|
|
202
202
|
#
|
|
203
203
|
# This allows plugins to maintain their configuration when agents are
|
|
@@ -215,5 +215,95 @@ module SwarmSDK
|
|
|
215
215
|
def serialize_config(agent_definition:)
|
|
216
216
|
{}
|
|
217
217
|
end
|
|
218
|
+
|
|
219
|
+
# Snapshot plugin-specific state for an agent
|
|
220
|
+
#
|
|
221
|
+
# Called during state snapshot creation (e.g., session persistence).
|
|
222
|
+
# Return any state your plugin needs to persist for this agent.
|
|
223
|
+
# The returned hash will be JSON serialized.
|
|
224
|
+
#
|
|
225
|
+
# @param agent_name [Symbol] Agent identifier
|
|
226
|
+
# @return [Hash] Plugin-specific state (empty hash if nothing to snapshot)
|
|
227
|
+
#
|
|
228
|
+
# @example Memory read tracking
|
|
229
|
+
# def snapshot_agent_state(agent_name)
|
|
230
|
+
# entries = StorageReadTracker.get_read_entries(agent_name)
|
|
231
|
+
# return {} if entries.empty?
|
|
232
|
+
#
|
|
233
|
+
# { read_entries: entries }
|
|
234
|
+
# end
|
|
235
|
+
def snapshot_agent_state(agent_name)
|
|
236
|
+
{}
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Restore plugin-specific state for an agent
|
|
240
|
+
#
|
|
241
|
+
# Called during state restoration. Restore any persisted state.
|
|
242
|
+
# This method is idempotent - calling it multiple times with
|
|
243
|
+
# the same state should produce the same result.
|
|
244
|
+
#
|
|
245
|
+
# @param agent_name [Symbol] Agent identifier
|
|
246
|
+
# @param state [Hash] Previously snapshotted state (with symbol keys)
|
|
247
|
+
# @return [void]
|
|
248
|
+
#
|
|
249
|
+
# @example Memory read tracking
|
|
250
|
+
# def restore_agent_state(agent_name, state)
|
|
251
|
+
# entries = state[:read_entries] || state["read_entries"]
|
|
252
|
+
# return unless entries
|
|
253
|
+
#
|
|
254
|
+
# StorageReadTracker.restore_read_entries(agent_name, entries)
|
|
255
|
+
# end
|
|
256
|
+
def restore_agent_state(agent_name, state)
|
|
257
|
+
# Override if needed
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Get digest for a tool result (e.g., file hash, memory entry hash)
|
|
261
|
+
#
|
|
262
|
+
# Called during tool result metadata collection. Returns a digest
|
|
263
|
+
# that can be used to detect if the resource has changed since
|
|
264
|
+
# it was last read. This enables change detection hooks.
|
|
265
|
+
#
|
|
266
|
+
# @param agent_name [Symbol] Agent identifier
|
|
267
|
+
# @param tool_name [String] Name of the tool (e.g., "MemoryRead")
|
|
268
|
+
# @param path [String] Path or identifier of the resource
|
|
269
|
+
# @return [String, nil] Digest string or nil if not tracked by this plugin
|
|
270
|
+
#
|
|
271
|
+
# @example Memory read tracking
|
|
272
|
+
# def get_tool_result_digest(agent_name:, tool_name:, path:)
|
|
273
|
+
# return unless tool_name == "MemoryRead"
|
|
274
|
+
#
|
|
275
|
+
# StorageReadTracker.get_read_entries(agent_name)[path]
|
|
276
|
+
# end
|
|
277
|
+
def get_tool_result_digest(agent_name:, tool_name:, path:)
|
|
278
|
+
nil
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Translate YAML configuration into DSL calls
|
|
282
|
+
#
|
|
283
|
+
# Called during YAML-to-DSL translation. Plugins can translate their
|
|
284
|
+
# specific YAML configuration keys into DSL method calls on the builder.
|
|
285
|
+
# This allows SDK to remain plugin-agnostic while plugins can add
|
|
286
|
+
# YAML configuration support.
|
|
287
|
+
#
|
|
288
|
+
# @param builder [Agent::Builder] Builder instance (self in DSL context)
|
|
289
|
+
# @param agent_config [Hash] Full agent config from YAML
|
|
290
|
+
# @return [void]
|
|
291
|
+
#
|
|
292
|
+
# @example Memory plugin YAML translation
|
|
293
|
+
# def translate_yaml_config(builder, agent_config)
|
|
294
|
+
# memory_config = agent_config[:memory]
|
|
295
|
+
# return unless memory_config
|
|
296
|
+
#
|
|
297
|
+
# builder.instance_eval do
|
|
298
|
+
# memory do
|
|
299
|
+
# directory(memory_config[:directory])
|
|
300
|
+
# adapter(memory_config[:adapter]) if memory_config[:adapter]
|
|
301
|
+
# mode(memory_config[:mode]) if memory_config[:mode]
|
|
302
|
+
# end
|
|
303
|
+
# end
|
|
304
|
+
# end
|
|
305
|
+
def translate_yaml_config(builder, agent_config)
|
|
306
|
+
# Override if plugin needs YAML configuration support
|
|
307
|
+
end
|
|
218
308
|
end
|
|
219
309
|
end
|
data/lib/swarm_sdk/result.rb
CHANGED
|
@@ -109,6 +109,58 @@ module SwarmSDK
|
|
|
109
109
|
@logs.map { |entry| entry[:agent] }.compact.uniq.map(&:to_sym)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
+
# Get per-agent usage breakdown from logs
|
|
113
|
+
#
|
|
114
|
+
# Aggregates context usage, tokens, and cost for each agent from their
|
|
115
|
+
# final agent_stop or agent_step events. Each agent's entry includes:
|
|
116
|
+
# - input_tokens, output_tokens, total_tokens
|
|
117
|
+
# - context_limit, usage_percentage, tokens_remaining
|
|
118
|
+
# - input_cost, output_cost, total_cost
|
|
119
|
+
#
|
|
120
|
+
# @return [Hash{Symbol => Hash}] Per-agent usage breakdown
|
|
121
|
+
#
|
|
122
|
+
# @example
|
|
123
|
+
# result.per_agent_usage[:backend]
|
|
124
|
+
# # => {
|
|
125
|
+
# # input_tokens: 15000,
|
|
126
|
+
# # output_tokens: 5000,
|
|
127
|
+
# # total_tokens: 20000,
|
|
128
|
+
# # context_limit: 200000,
|
|
129
|
+
# # usage_percentage: "10.0%",
|
|
130
|
+
# # tokens_remaining: 180000,
|
|
131
|
+
# # input_cost: 0.045,
|
|
132
|
+
# # output_cost: 0.075,
|
|
133
|
+
# # total_cost: 0.12
|
|
134
|
+
# # }
|
|
135
|
+
def per_agent_usage
|
|
136
|
+
# Find the last usage entry for each agent
|
|
137
|
+
agent_entries = {}
|
|
138
|
+
|
|
139
|
+
@logs.each do |entry|
|
|
140
|
+
next unless entry[:usage] && entry[:agent]
|
|
141
|
+
next unless entry[:type] == "agent_step" || entry[:type] == "agent_stop"
|
|
142
|
+
|
|
143
|
+
agent_name = entry[:agent].to_sym
|
|
144
|
+
agent_entries[agent_name] = entry[:usage]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Build breakdown from final usage entries
|
|
148
|
+
agent_entries.transform_values do |usage|
|
|
149
|
+
{
|
|
150
|
+
input_tokens: usage[:cumulative_input_tokens] || 0,
|
|
151
|
+
output_tokens: usage[:cumulative_output_tokens] || 0,
|
|
152
|
+
total_tokens: usage[:cumulative_total_tokens] || 0,
|
|
153
|
+
cached_tokens: usage[:cumulative_cached_tokens] || 0,
|
|
154
|
+
context_limit: usage[:context_limit],
|
|
155
|
+
usage_percentage: usage[:tokens_used_percentage],
|
|
156
|
+
tokens_remaining: usage[:tokens_remaining],
|
|
157
|
+
input_cost: usage[:input_cost] || 0.0,
|
|
158
|
+
output_cost: usage[:output_cost] || 0.0,
|
|
159
|
+
total_cost: usage[:total_cost] || 0.0,
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
112
164
|
# Count total LLM requests made
|
|
113
165
|
# Each LLM API call produces either agent_step (tool calls) or agent_stop (final answer)
|
|
114
166
|
def llm_requests
|
data/lib/swarm_sdk/snapshot.rb
CHANGED
|
@@ -102,7 +102,7 @@ module SwarmSDK
|
|
|
102
102
|
@data[:version] || @data["version"]
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
# Get snapshot type (swarm or
|
|
105
|
+
# Get snapshot type (swarm or workflow)
|
|
106
106
|
#
|
|
107
107
|
# @return [String] Snapshot type
|
|
108
108
|
def type
|
|
@@ -139,18 +139,18 @@ module SwarmSDK
|
|
|
139
139
|
delegations ? delegations.keys.map(&:to_s) : []
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
# Check if snapshot is for a swarm (vs
|
|
142
|
+
# Check if snapshot is for a swarm (vs workflow)
|
|
143
143
|
#
|
|
144
144
|
# @return [Boolean] true if swarm snapshot
|
|
145
145
|
def swarm?
|
|
146
146
|
type == "swarm"
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
# Check if snapshot is for a
|
|
149
|
+
# Check if snapshot is for a workflow
|
|
150
150
|
#
|
|
151
|
-
# @return [Boolean] true if
|
|
152
|
-
def
|
|
153
|
-
type == "
|
|
151
|
+
# @return [Boolean] true if workflow snapshot
|
|
152
|
+
def workflow?
|
|
153
|
+
type == "workflow"
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
end
|
|
@@ -69,16 +69,17 @@ module SwarmSDK
|
|
|
69
69
|
# @return [Hash] StateSnapshot hash
|
|
70
70
|
def reconstruct
|
|
71
71
|
{
|
|
72
|
-
version: "1.0
|
|
72
|
+
version: "2.1.0",
|
|
73
73
|
type: "swarm",
|
|
74
74
|
snapshot_at: @events.last&.fetch(:timestamp, Time.now.utc.iso8601),
|
|
75
75
|
swarm_sdk_version: SwarmSDK::VERSION,
|
|
76
|
-
|
|
76
|
+
metadata: reconstruct_swarm_metadata,
|
|
77
77
|
agents: reconstruct_all_agents,
|
|
78
78
|
delegation_instances: reconstruct_all_delegations,
|
|
79
79
|
scratchpad: reconstruct_scratchpad,
|
|
80
80
|
read_tracking: reconstruct_read_tracking,
|
|
81
81
|
memory_read_tracking: reconstruct_memory_read_tracking,
|
|
82
|
+
plugin_states: reconstruct_plugin_states,
|
|
82
83
|
}
|
|
83
84
|
end
|
|
84
85
|
|
|
@@ -363,6 +364,16 @@ module SwarmSDK
|
|
|
363
364
|
tracking
|
|
364
365
|
end
|
|
365
366
|
|
|
367
|
+
# Reconstruct plugin states
|
|
368
|
+
#
|
|
369
|
+
# Plugin states cannot be fully reconstructed from events alone as they
|
|
370
|
+
# contain internal plugin data. Returns empty hash for compatibility.
|
|
371
|
+
#
|
|
372
|
+
# @return [Hash] Empty plugin states hash
|
|
373
|
+
def reconstruct_plugin_states
|
|
374
|
+
{}
|
|
375
|
+
end
|
|
376
|
+
|
|
366
377
|
# Parse timestamp string to Time object
|
|
367
378
|
#
|
|
368
379
|
# @param timestamp [String, nil] ISO 8601 timestamp
|