swarm_memory 2.1.3 → 2.1.4
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/lib/claude_swarm/claude_mcp_server.rb +1 -0
- data/lib/claude_swarm/cli.rb +5 -18
- data/lib/claude_swarm/configuration.rb +2 -15
- data/lib/claude_swarm/mcp_generator.rb +1 -0
- data/lib/claude_swarm/openai/chat_completion.rb +4 -12
- data/lib/claude_swarm/openai/executor.rb +3 -1
- data/lib/claude_swarm/openai/responses.rb +13 -32
- 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 +70 -0
- data/lib/swarm_cli/interactive_repl.rb +11 -5
- 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 -1059
- 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 +111 -44
- 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 -679
- 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
- metadata +37 -14
- data/lib/swarm_memory/chat_extension.rb +0 -34
- data/lib/swarm_sdk/providers/openai_with_responses.rb +0 -589
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module SwarmSDK
|
|
4
|
-
# Creates snapshots of swarm conversation state
|
|
4
|
+
# Creates snapshots of swarm/workflow conversation state
|
|
5
5
|
#
|
|
6
|
-
# Unified implementation that works for both Swarm and
|
|
6
|
+
# Unified implementation that works for both Swarm and Workflow.
|
|
7
7
|
# Captures conversation history, context state, scratchpad contents, and
|
|
8
8
|
# read tracking information.
|
|
9
9
|
#
|
|
@@ -15,20 +15,19 @@ module SwarmSDK
|
|
|
15
15
|
# swarm = SwarmSDK.build { ... }
|
|
16
16
|
# swarm.execute("Build authentication")
|
|
17
17
|
# snapshot = swarm.snapshot
|
|
18
|
-
#
|
|
18
|
+
# snapshot.write_to_file("session.json")
|
|
19
19
|
#
|
|
20
|
-
# @example Snapshot a
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# snapshot =
|
|
24
|
-
#
|
|
20
|
+
# @example Snapshot a workflow
|
|
21
|
+
# workflow = SwarmSDK.workflow { ... }
|
|
22
|
+
# workflow.execute("Build feature")
|
|
23
|
+
# snapshot = workflow.snapshot
|
|
24
|
+
# snapshot.write_to_file("workflow_session.json")
|
|
25
25
|
class StateSnapshot
|
|
26
26
|
# Initialize snapshot creator
|
|
27
27
|
#
|
|
28
|
-
# @param orchestration [Swarm,
|
|
28
|
+
# @param orchestration [Swarm, Workflow] Swarm or workflow to snapshot
|
|
29
29
|
def initialize(orchestration)
|
|
30
30
|
@orchestration = orchestration
|
|
31
|
-
@type = orchestration.is_a?(SwarmSDK::NodeOrchestrator) ? :node_orchestrator : :swarm
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
# Create snapshot of current state
|
|
@@ -39,76 +38,54 @@ module SwarmSDK
|
|
|
39
38
|
# @return [Snapshot] Snapshot object
|
|
40
39
|
def snapshot
|
|
41
40
|
data = {
|
|
42
|
-
version: "1.0
|
|
43
|
-
type:
|
|
41
|
+
version: "2.1.0", # Bumped for plugin state abstraction
|
|
42
|
+
type: type_name,
|
|
44
43
|
snapshot_at: Time.now.utc.iso8601,
|
|
45
44
|
swarm_sdk_version: SwarmSDK::VERSION,
|
|
45
|
+
metadata: snapshot_metadata,
|
|
46
46
|
agents: snapshot_agents,
|
|
47
47
|
delegation_instances: snapshot_delegation_instances,
|
|
48
|
+
scratchpad: snapshot_scratchpad,
|
|
48
49
|
read_tracking: snapshot_read_tracking,
|
|
49
|
-
|
|
50
|
+
plugin_states: snapshot_plugin_states,
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
# Add scratchpad for both Swarm and NodeOrchestrator (shared across nodes)
|
|
53
|
-
data[:scratchpad] = snapshot_scratchpad
|
|
54
|
-
|
|
55
|
-
# Add type-specific metadata
|
|
56
|
-
if @type == :swarm
|
|
57
|
-
data[:swarm] = snapshot_swarm_metadata
|
|
58
|
-
else
|
|
59
|
-
data[:orchestrator] = snapshot_orchestrator_metadata
|
|
60
|
-
end
|
|
61
|
-
|
|
62
53
|
# Wrap in Snapshot object
|
|
63
54
|
SwarmSDK::Snapshot.new(data)
|
|
64
55
|
end
|
|
65
56
|
|
|
66
57
|
private
|
|
67
58
|
|
|
68
|
-
#
|
|
59
|
+
# Get type name for snapshot
|
|
69
60
|
#
|
|
70
|
-
# @return [
|
|
71
|
-
def
|
|
72
|
-
|
|
73
|
-
id: @orchestration.swarm_id,
|
|
74
|
-
parent_id: @orchestration.parent_swarm_id,
|
|
75
|
-
first_message_sent: @orchestration.first_message_sent?,
|
|
76
|
-
}
|
|
61
|
+
# @return [String] "swarm" or "workflow"
|
|
62
|
+
def type_name
|
|
63
|
+
@orchestration.class.name.split("::").last.downcase
|
|
77
64
|
end
|
|
78
65
|
|
|
79
|
-
# Snapshot
|
|
66
|
+
# Snapshot common metadata
|
|
80
67
|
#
|
|
81
|
-
# @return [Hash]
|
|
82
|
-
def
|
|
68
|
+
# @return [Hash] Metadata
|
|
69
|
+
def snapshot_metadata
|
|
83
70
|
{
|
|
84
|
-
id: @orchestration.swarm_id
|
|
85
|
-
parent_id:
|
|
71
|
+
id: @orchestration.swarm_id,
|
|
72
|
+
parent_id: @orchestration.parent_swarm_id,
|
|
73
|
+
name: @orchestration.name,
|
|
74
|
+
# Swarm-specific: first_message_sent (Workflow returns false)
|
|
75
|
+
first_message_sent: @orchestration.first_message_sent?,
|
|
86
76
|
}
|
|
87
77
|
end
|
|
88
78
|
|
|
89
|
-
# Generate orchestrator ID if not set
|
|
90
|
-
#
|
|
91
|
-
# @return [String] Generated ID
|
|
92
|
-
def generate_orchestrator_id
|
|
93
|
-
name = @orchestration.swarm_name.to_s.gsub(/[^a-z0-9_-]/i, "_").downcase
|
|
94
|
-
"#{name}_#{SecureRandom.hex(4)}"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
79
|
# Snapshot all agent conversations and context state
|
|
98
80
|
#
|
|
81
|
+
# Uses interface method: primary_agents (no type checking!)
|
|
82
|
+
#
|
|
99
83
|
# @return [Hash] { agent_name => { conversation:, context_state:, system_prompt: } }
|
|
100
84
|
def snapshot_agents
|
|
101
85
|
result = {}
|
|
102
86
|
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
@orchestration.agents
|
|
106
|
-
else
|
|
107
|
-
@orchestration.agent_instance_cache[:primary]
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
agents_hash.each do |agent_name, agent_chat|
|
|
111
|
-
# Get system prompt from agent definition
|
|
87
|
+
# Use interface method - works for both Swarm and Workflow!
|
|
88
|
+
@orchestration.primary_agents.each do |agent_name, agent_chat|
|
|
112
89
|
agent_definition = @orchestration.agent_definitions[agent_name]
|
|
113
90
|
system_prompt = agent_definition&.system_prompt
|
|
114
91
|
|
|
@@ -127,35 +104,24 @@ module SwarmSDK
|
|
|
127
104
|
# @param agent_chat [Agent::Chat] Agent chat instance
|
|
128
105
|
# @return [Array<Hash>] Serialized messages
|
|
129
106
|
def snapshot_conversation(agent_chat)
|
|
130
|
-
messages
|
|
131
|
-
messages.map { |msg| serialize_message(msg) }
|
|
107
|
+
agent_chat.messages.map { |msg| serialize_message(msg) }
|
|
132
108
|
end
|
|
133
109
|
|
|
134
110
|
# Serialize a single message
|
|
135
111
|
#
|
|
136
|
-
# Handles RubyLLM::Message serialization with proper handling of:
|
|
137
|
-
# - Content objects (text + attachments)
|
|
138
|
-
# - Tool calls (must manually call .to_h on each)
|
|
139
|
-
# - Tool call IDs, tokens, model IDs
|
|
140
|
-
#
|
|
141
112
|
# @param msg [RubyLLM::Message] Message to serialize
|
|
142
113
|
# @return [Hash] Serialized message
|
|
143
114
|
def serialize_message(msg)
|
|
144
115
|
hash = { role: msg.role }
|
|
145
116
|
|
|
146
|
-
# Handle content - check msg.content directly
|
|
147
|
-
# msg.to_h converts Content to String when no attachments present
|
|
117
|
+
# Handle content - check msg.content directly
|
|
148
118
|
hash[:content] = if msg.content.is_a?(RubyLLM::Content)
|
|
149
|
-
# Content object: serialize with text + attachments
|
|
150
119
|
msg.content.to_h
|
|
151
120
|
else
|
|
152
|
-
# Plain string content
|
|
153
121
|
msg.content
|
|
154
122
|
end
|
|
155
123
|
|
|
156
|
-
# Handle tool calls
|
|
157
|
-
# RubyLLM::ToolCall#to_h doesn't reliably serialize id/name fields
|
|
158
|
-
# msg.tool_calls is a Hash<String, ToolCall>, so we need .values
|
|
124
|
+
# Handle tool calls
|
|
159
125
|
if msg.tool_calls && !msg.tool_calls.empty?
|
|
160
126
|
hash[:tool_calls] = msg.tool_calls.values.map do |tc|
|
|
161
127
|
{
|
|
@@ -185,7 +151,6 @@ module SwarmSDK
|
|
|
185
151
|
|
|
186
152
|
{
|
|
187
153
|
warning_thresholds_hit: agent_context.warning_thresholds_hit.to_a,
|
|
188
|
-
# NOTE: @compression_applied initializes to nil, not false
|
|
189
154
|
compression_applied: context_manager.compression_applied,
|
|
190
155
|
last_todowrite_message_index: agent_chat.last_todowrite_message_index,
|
|
191
156
|
active_skill_path: agent_chat.active_skill_path,
|
|
@@ -194,19 +159,15 @@ module SwarmSDK
|
|
|
194
159
|
|
|
195
160
|
# Snapshot delegation instance conversations
|
|
196
161
|
#
|
|
162
|
+
# Uses interface method: delegation_instances_hash (no type checking!)
|
|
163
|
+
#
|
|
197
164
|
# @return [Hash] { "delegate@delegator" => { conversation:, context_state:, system_prompt: } }
|
|
198
165
|
def snapshot_delegation_instances
|
|
199
166
|
result = {}
|
|
200
167
|
|
|
201
|
-
#
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
else
|
|
205
|
-
@orchestration.agent_instance_cache[:delegations]
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
delegations_hash.each do |instance_name, delegation_chat|
|
|
209
|
-
# Extract base agent name from instance name (e.g., "backend@lead" -> "backend")
|
|
168
|
+
# Use interface method - works for both Swarm and Workflow!
|
|
169
|
+
@orchestration.delegation_instances_hash.each do |instance_name, delegation_chat|
|
|
170
|
+
# Extract base agent name from instance name
|
|
210
171
|
base_name = instance_name.to_s.split("@").first.to_sym
|
|
211
172
|
|
|
212
173
|
# Get system prompt from base agent definition
|
|
@@ -225,24 +186,21 @@ module SwarmSDK
|
|
|
225
186
|
|
|
226
187
|
# Snapshot scratchpad contents
|
|
227
188
|
#
|
|
228
|
-
#
|
|
229
|
-
# For NodeOrchestrator: returns structured hash with metadata
|
|
230
|
-
# - Enabled mode: { shared: true, data: { path => entry } }
|
|
231
|
-
# - Per-node mode: { shared: false, data: { node_name => { path => entry } } }
|
|
189
|
+
# Detects type and calls appropriate method.
|
|
232
190
|
#
|
|
233
191
|
# @return [Hash] Scratchpad snapshot data
|
|
234
192
|
def snapshot_scratchpad
|
|
235
|
-
if @
|
|
236
|
-
|
|
193
|
+
if @orchestration.is_a?(Workflow)
|
|
194
|
+
snapshot_workflow_scratchpad
|
|
237
195
|
else
|
|
238
196
|
snapshot_swarm_scratchpad
|
|
239
197
|
end
|
|
240
198
|
end
|
|
241
199
|
|
|
242
|
-
# Snapshot scratchpad for
|
|
200
|
+
# Snapshot scratchpad for Workflow
|
|
243
201
|
#
|
|
244
202
|
# @return [Hash] Structured scratchpad data with mode metadata
|
|
245
|
-
def
|
|
203
|
+
def snapshot_workflow_scratchpad
|
|
246
204
|
all_scratchpads = @orchestration.all_scratchpads
|
|
247
205
|
return {} unless all_scratchpads&.any?
|
|
248
206
|
|
|
@@ -328,22 +286,31 @@ module SwarmSDK
|
|
|
328
286
|
result
|
|
329
287
|
end
|
|
330
288
|
|
|
331
|
-
# Snapshot
|
|
289
|
+
# Snapshot plugin-specific state for all plugins
|
|
332
290
|
#
|
|
333
|
-
#
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
291
|
+
# Iterates over all registered plugins and collects their agent-specific state.
|
|
292
|
+
# This decouples the SDK from plugin-specific implementations.
|
|
293
|
+
#
|
|
294
|
+
# @return [Hash] { plugin_name => { agent_name => plugin_state } }
|
|
295
|
+
def snapshot_plugin_states
|
|
337
296
|
result = {}
|
|
338
297
|
|
|
339
298
|
# Get all agents (primary + delegations)
|
|
340
299
|
agent_names = all_agent_names
|
|
341
300
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
301
|
+
# Iterate over all registered plugins
|
|
302
|
+
PluginRegistry.all.each do |plugin|
|
|
303
|
+
plugin_state = {}
|
|
304
|
+
|
|
305
|
+
agent_names.each do |agent_name|
|
|
306
|
+
agent_state = plugin.snapshot_agent_state(agent_name)
|
|
307
|
+
next if agent_state.empty?
|
|
308
|
+
|
|
309
|
+
plugin_state[agent_name.to_s] = agent_state
|
|
310
|
+
end
|
|
345
311
|
|
|
346
|
-
|
|
312
|
+
# Only include plugin if it has state for at least one agent
|
|
313
|
+
result[plugin.name.to_s] = plugin_state unless plugin_state.empty?
|
|
347
314
|
end
|
|
348
315
|
|
|
349
316
|
result
|
|
@@ -351,17 +318,15 @@ module SwarmSDK
|
|
|
351
318
|
|
|
352
319
|
# All agent names (primary + delegations)
|
|
353
320
|
#
|
|
321
|
+
# Uses interface methods - no type checking!
|
|
322
|
+
#
|
|
354
323
|
# @return [Array<Symbol>] All agent names
|
|
355
324
|
def all_agent_names
|
|
356
|
-
# Get primary agent names
|
|
325
|
+
# Get primary agent names
|
|
357
326
|
agents_hash = @orchestration.agent_definitions.keys
|
|
358
327
|
|
|
359
328
|
# Add delegation instance names
|
|
360
|
-
delegations_hash =
|
|
361
|
-
@orchestration.delegation_instances.keys
|
|
362
|
-
else
|
|
363
|
-
@orchestration.agent_instance_cache[:delegations].keys
|
|
364
|
-
end
|
|
329
|
+
delegations_hash = @orchestration.delegation_instances_hash.keys
|
|
365
330
|
|
|
366
331
|
agents_hash + delegations_hash.map(&:to_sym)
|
|
367
332
|
end
|