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
|
@@ -156,7 +156,7 @@ module SwarmMemory
|
|
|
156
156
|
# @return [String] Memory prompt contribution
|
|
157
157
|
def system_prompt_contribution(agent_definition:, storage:)
|
|
158
158
|
# Extract mode from memory config
|
|
159
|
-
memory_config = agent_definition.memory
|
|
159
|
+
memory_config = agent_definition.plugin_config(:memory)
|
|
160
160
|
mode = if memory_config.is_a?(SwarmMemory::DSL::MemoryConfig)
|
|
161
161
|
memory_config.mode # MemoryConfig object from DSL
|
|
162
162
|
elsif memory_config.respond_to?(:mode)
|
|
@@ -204,20 +204,100 @@ module SwarmMemory
|
|
|
204
204
|
# @param agent_definition [Agent::Definition] Agent definition
|
|
205
205
|
# @return [Boolean] True if agent has memory configuration
|
|
206
206
|
def storage_enabled?(agent_definition)
|
|
207
|
-
agent_definition.
|
|
207
|
+
memory_config = agent_definition.plugin_config(:memory)
|
|
208
|
+
return false if memory_config.nil?
|
|
209
|
+
|
|
210
|
+
# MemoryConfig object (from DSL)
|
|
211
|
+
return memory_config.enabled? if memory_config.respond_to?(:enabled?)
|
|
212
|
+
|
|
213
|
+
# Hash (from YAML) - check for directory key
|
|
214
|
+
if memory_config.is_a?(Hash)
|
|
215
|
+
directory = memory_config[:directory] || memory_config["directory"]
|
|
216
|
+
return !directory.nil? && !directory.to_s.strip.empty?
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
false
|
|
208
220
|
end
|
|
209
221
|
|
|
210
222
|
# Contribute to agent serialization
|
|
211
223
|
#
|
|
212
|
-
# Preserves memory configuration when agents are cloned (e.g., in
|
|
224
|
+
# Preserves memory configuration when agents are cloned (e.g., in Workflow).
|
|
213
225
|
# This allows memory configuration to persist across node transitions.
|
|
214
226
|
#
|
|
215
227
|
# @param agent_definition [Agent::Definition] Agent definition
|
|
216
228
|
# @return [Hash] Memory config to include in to_h
|
|
217
229
|
def serialize_config(agent_definition:)
|
|
218
|
-
|
|
230
|
+
memory_config = agent_definition.plugin_config(:memory)
|
|
231
|
+
return {} unless memory_config
|
|
232
|
+
|
|
233
|
+
{ memory: memory_config }
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Snapshot plugin-specific state for an agent
|
|
237
|
+
#
|
|
238
|
+
# Captures memory read tracking state for session persistence.
|
|
239
|
+
# This allows agents to remember which memory entries they've read
|
|
240
|
+
# across sessions.
|
|
241
|
+
#
|
|
242
|
+
# @param agent_name [Symbol] Agent identifier
|
|
243
|
+
# @return [Hash] Plugin-specific state
|
|
244
|
+
def snapshot_agent_state(agent_name)
|
|
245
|
+
entries_with_digests = Core::StorageReadTracker.get_read_entries(agent_name)
|
|
246
|
+
return {} if entries_with_digests.empty?
|
|
247
|
+
|
|
248
|
+
{ read_entries: entries_with_digests }
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Restore plugin-specific state for an agent
|
|
252
|
+
#
|
|
253
|
+
# Restores memory read tracking state from snapshot.
|
|
254
|
+
# This is idempotent - calling multiple times with same state
|
|
255
|
+
# produces the same result.
|
|
256
|
+
#
|
|
257
|
+
# @param agent_name [Symbol] Agent identifier
|
|
258
|
+
# @param state [Hash] Previously snapshotted state (with symbol keys)
|
|
259
|
+
# @return [void]
|
|
260
|
+
def restore_agent_state(agent_name, state)
|
|
261
|
+
entries = state[:read_entries] || state["read_entries"]
|
|
262
|
+
return unless entries
|
|
263
|
+
|
|
264
|
+
Core::StorageReadTracker.restore_read_entries(agent_name, entries)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Get digest for a memory tool result
|
|
268
|
+
#
|
|
269
|
+
# Returns the digest for a MemoryRead tool call, enabling change detection
|
|
270
|
+
# hooks to know if a memory entry has been modified since last read.
|
|
271
|
+
#
|
|
272
|
+
# @param agent_name [Symbol] Agent identifier
|
|
273
|
+
# @param tool_name [String] Name of the tool
|
|
274
|
+
# @param path [String] Path of the memory entry
|
|
275
|
+
# @return [String, nil] Digest string or nil if not a memory tool
|
|
276
|
+
def get_tool_result_digest(agent_name:, tool_name:, path:)
|
|
277
|
+
return unless tool_name == "MemoryRead"
|
|
219
278
|
|
|
220
|
-
|
|
279
|
+
Core::StorageReadTracker.get_read_entries(agent_name)[path]
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Translate YAML configuration into DSL calls
|
|
283
|
+
#
|
|
284
|
+
# Called during YAML-to-DSL translation. Handles memory-specific YAML
|
|
285
|
+
# configuration and translates it into DSL method calls on the builder.
|
|
286
|
+
#
|
|
287
|
+
# @param builder [Agent::Builder] Builder instance (self in DSL context)
|
|
288
|
+
# @param agent_config [Hash] Full agent config from YAML
|
|
289
|
+
# @return [void]
|
|
290
|
+
def translate_yaml_config(builder, agent_config)
|
|
291
|
+
memory_config = agent_config[:memory]
|
|
292
|
+
return unless memory_config
|
|
293
|
+
|
|
294
|
+
builder.instance_eval do
|
|
295
|
+
memory do
|
|
296
|
+
directory(memory_config[:directory]) if memory_config[:directory]
|
|
297
|
+
adapter(memory_config[:adapter]) if memory_config[:adapter]
|
|
298
|
+
mode(memory_config[:mode]) if memory_config[:mode]
|
|
299
|
+
end
|
|
300
|
+
end
|
|
221
301
|
end
|
|
222
302
|
|
|
223
303
|
# Lifecycle: Agent initialized
|
|
@@ -239,7 +319,7 @@ module SwarmMemory
|
|
|
239
319
|
return unless storage # Only proceed if memory is enabled for this agent
|
|
240
320
|
|
|
241
321
|
# Extract mode from memory config
|
|
242
|
-
memory_config = agent_definition.memory
|
|
322
|
+
memory_config = agent_definition.plugin_config(:memory)
|
|
243
323
|
mode = if memory_config.is_a?(SwarmMemory::DSL::MemoryConfig)
|
|
244
324
|
memory_config.mode # MemoryConfig object from DSL
|
|
245
325
|
elsif memory_config.respond_to?(:mode)
|
|
@@ -281,7 +361,7 @@ module SwarmMemory
|
|
|
281
361
|
agent_definition: agent_definition,
|
|
282
362
|
)
|
|
283
363
|
|
|
284
|
-
agent.
|
|
364
|
+
agent.add_tool(load_skill_tool)
|
|
285
365
|
end
|
|
286
366
|
|
|
287
367
|
# Mark mode-specific memory tools + LoadSkill as immutable
|
data/lib/swarm_memory/version.rb
CHANGED
data/lib/swarm_memory.rb
CHANGED
|
@@ -42,7 +42,7 @@ loader.setup
|
|
|
42
42
|
# These must be loaded after Zeitwerk but before anything uses them
|
|
43
43
|
require_relative "swarm_memory/dsl/memory_config"
|
|
44
44
|
require_relative "swarm_memory/dsl/builder_extension"
|
|
45
|
-
|
|
45
|
+
# NOTE: ChatExtension was removed in favor of SDK's built-in remove_tool method
|
|
46
46
|
|
|
47
47
|
module SwarmMemory
|
|
48
48
|
class << self
|
|
@@ -60,6 +60,7 @@ module SwarmSDK
|
|
|
60
60
|
@default_permissions = {} # Set by SwarmBuilder from all_agents
|
|
61
61
|
@memory_config = nil
|
|
62
62
|
@shared_across_delegations = nil # nil = not set (will default to false in Definition)
|
|
63
|
+
@context_management_config = nil # Context management DSL hooks
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
# Set/get agent model
|
|
@@ -288,6 +289,56 @@ module SwarmSDK
|
|
|
288
289
|
self
|
|
289
290
|
end
|
|
290
291
|
|
|
292
|
+
# Configure context management handlers
|
|
293
|
+
#
|
|
294
|
+
# Define custom handlers for context warning thresholds (60%, 80%, 90%).
|
|
295
|
+
# Handlers receive a rich context object with message manipulation methods.
|
|
296
|
+
# When a custom handler is registered, automatic compression is disabled
|
|
297
|
+
# for that threshold, giving full control to the handler.
|
|
298
|
+
#
|
|
299
|
+
# @yield Context management DSL block
|
|
300
|
+
# @return [void]
|
|
301
|
+
#
|
|
302
|
+
# @example Basic compression at 60%
|
|
303
|
+
# context_management do
|
|
304
|
+
# on :warning_60 do |ctx|
|
|
305
|
+
# ctx.compress_tool_results(keep_recent: 10)
|
|
306
|
+
# end
|
|
307
|
+
# end
|
|
308
|
+
#
|
|
309
|
+
# @example Multiple thresholds with different strategies
|
|
310
|
+
# context_management do
|
|
311
|
+
# on :warning_60 do |ctx|
|
|
312
|
+
# ctx.compress_tool_results(keep_recent: 15, truncate_to: 500)
|
|
313
|
+
# end
|
|
314
|
+
#
|
|
315
|
+
# on :warning_80 do |ctx|
|
|
316
|
+
# ctx.prune_old_messages(keep_recent: 30)
|
|
317
|
+
# ctx.compress_tool_results(keep_recent: 5, truncate_to: 200)
|
|
318
|
+
# end
|
|
319
|
+
#
|
|
320
|
+
# on :warning_90 do |ctx|
|
|
321
|
+
# ctx.log_action("emergency_pruning", remaining: ctx.tokens_remaining)
|
|
322
|
+
# ctx.prune_old_messages(keep_recent: 15)
|
|
323
|
+
# end
|
|
324
|
+
# end
|
|
325
|
+
#
|
|
326
|
+
# @example Conditional logic based on metrics
|
|
327
|
+
# context_management do
|
|
328
|
+
# on :warning_80 do |ctx|
|
|
329
|
+
# if ctx.usage_percentage > 85
|
|
330
|
+
# ctx.prune_old_messages(keep_recent: 10)
|
|
331
|
+
# else
|
|
332
|
+
# ctx.compress_tool_results(keep_recent: 5)
|
|
333
|
+
# end
|
|
334
|
+
# end
|
|
335
|
+
# end
|
|
336
|
+
def context_management(&block)
|
|
337
|
+
builder = ContextManagement::Builder.new
|
|
338
|
+
builder.instance_eval(&block)
|
|
339
|
+
@context_management_config = builder.build
|
|
340
|
+
end
|
|
341
|
+
|
|
291
342
|
# Set permissions directly from hash (for YAML translation)
|
|
292
343
|
#
|
|
293
344
|
# This is intentionally separate from permissions() to keep the DSL clean.
|
|
@@ -411,6 +462,13 @@ module SwarmSDK
|
|
|
411
462
|
# Convert DSL hooks to HookDefinition format
|
|
412
463
|
agent_config[:hooks] = convert_hooks_to_definitions if @hooks.any?
|
|
413
464
|
|
|
465
|
+
# Merge context management hooks into agent hooks
|
|
466
|
+
if @context_management_config
|
|
467
|
+
agent_config[:hooks] ||= {}
|
|
468
|
+
agent_config[:hooks][:context_warning] ||= []
|
|
469
|
+
agent_config[:hooks][:context_warning].concat(@context_management_config)
|
|
470
|
+
end
|
|
471
|
+
|
|
414
472
|
Agent::Definition.new(@name, agent_config)
|
|
415
473
|
end
|
|
416
474
|
|