claude_swarm 1.0.10 → 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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG.md → CHANGELOG.claude-swarm.md} +3 -0
  3. data/CLAUDE.md +0 -1
  4. data/decisions/2025-11-22-001-global-agent-registry.md +172 -0
  5. data/docs/v2/CHANGELOG.swarm_cli.md +12 -0
  6. data/docs/v2/CHANGELOG.swarm_memory.md +139 -0
  7. data/docs/v2/CHANGELOG.swarm_sdk.md +249 -1
  8. data/docs/v2/README.md +15 -5
  9. data/docs/v2/guides/complete-tutorial.md +93 -7
  10. data/docs/v2/guides/getting-started.md +3 -1
  11. data/docs/v2/guides/memory-adapters.md +41 -0
  12. data/docs/v2/guides/{migrating-to-2.3.md → migrating-to-2.x.md} +213 -8
  13. data/docs/v2/guides/plugins.md +52 -5
  14. data/docs/v2/guides/rails-integration.md +6 -0
  15. data/docs/v2/guides/swarm-memory.md +2 -13
  16. data/docs/v2/reference/cli.md +0 -1
  17. data/docs/v2/reference/configuration_reference.md +300 -0
  18. data/docs/v2/reference/event_payload_structures.md +26 -4
  19. data/docs/v2/reference/ruby-dsl.md +457 -4
  20. data/docs/v2/reference/swarm_memory_technical_details.md +7 -29
  21. data/docs/v2/reference/yaml.md +2 -2
  22. data/lib/claude_swarm/mcp_generator.rb +1 -1
  23. data/lib/claude_swarm/orchestrator.rb +8 -1
  24. data/lib/claude_swarm/version.rb +1 -1
  25. data/lib/swarm_cli/version.rb +1 -1
  26. data/lib/swarm_memory/core/semantic_index.rb +10 -2
  27. data/lib/swarm_memory/core/storage.rb +7 -2
  28. data/lib/swarm_memory/dsl/memory_config.rb +37 -0
  29. data/lib/swarm_memory/integration/sdk_plugin.rb +120 -27
  30. data/lib/swarm_memory/optimization/defragmenter.rb +1 -1
  31. data/lib/swarm_memory/prompts/memory_researcher.md.erb +0 -1
  32. data/lib/swarm_memory/tools/load_skill.rb +0 -1
  33. data/lib/swarm_memory/tools/memory_edit.rb +2 -1
  34. data/lib/swarm_memory/tools/memory_read.rb +1 -1
  35. data/lib/swarm_memory/version.rb +1 -1
  36. data/lib/swarm_memory.rb +7 -5
  37. data/lib/swarm_sdk/agent/chat.rb +1 -1
  38. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +4 -0
  39. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +1 -1
  40. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +38 -4
  41. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +2 -2
  42. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +3 -5
  43. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +48 -0
  44. data/lib/swarm_sdk/agent/context.rb +1 -2
  45. data/lib/swarm_sdk/agent/definition.rb +3 -3
  46. data/lib/swarm_sdk/agent/system_prompt_builder.rb +1 -1
  47. data/lib/swarm_sdk/agent_registry.rb +146 -0
  48. data/lib/swarm_sdk/builders/base_builder.rb +91 -12
  49. data/lib/swarm_sdk/config.rb +302 -0
  50. data/lib/swarm_sdk/configuration/parser.rb +22 -2
  51. data/lib/swarm_sdk/configuration.rb +13 -4
  52. data/lib/swarm_sdk/context_compactor/token_counter.rb +2 -6
  53. data/lib/swarm_sdk/custom_tool_registry.rb +226 -0
  54. data/lib/swarm_sdk/hooks/adapter.rb +3 -3
  55. data/lib/swarm_sdk/hooks/shell_executor.rb +4 -3
  56. data/lib/swarm_sdk/models.json +4333 -1
  57. data/lib/swarm_sdk/models.rb +43 -2
  58. data/lib/swarm_sdk/plugin.rb +2 -2
  59. data/lib/swarm_sdk/result.rb +52 -0
  60. data/lib/swarm_sdk/swarm/agent_initializer.rb +1 -1
  61. data/lib/swarm_sdk/swarm/hook_triggers.rb +1 -0
  62. data/lib/swarm_sdk/swarm/logging_callbacks.rb +1 -0
  63. data/lib/swarm_sdk/swarm/tool_configurator.rb +18 -4
  64. data/lib/swarm_sdk/swarm.rb +76 -13
  65. data/lib/swarm_sdk/tools/bash.rb +7 -9
  66. data/lib/swarm_sdk/tools/glob.rb +5 -5
  67. data/lib/swarm_sdk/tools/read.rb +8 -8
  68. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +4 -3
  69. data/lib/swarm_sdk/tools/web_fetch.rb +20 -18
  70. data/lib/swarm_sdk/version.rb +1 -1
  71. data/lib/swarm_sdk/workflow/builder.rb +49 -0
  72. data/lib/swarm_sdk/workflow/node_builder.rb +4 -2
  73. data/lib/swarm_sdk/workflow/transformer_executor.rb +4 -3
  74. data/lib/swarm_sdk.rb +261 -105
  75. data/swarm_cli.gemspec +1 -1
  76. data/swarm_memory.gemspec +8 -3
  77. data/swarm_sdk.gemspec +4 -4
  78. data/team_full.yml +104 -300
  79. metadata +9 -5
  80. data/lib/swarm_memory/tools/memory_multi_edit.rb +0 -281
  81. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7137a9b3f3fd37de3a81a9b3f4b1b6fe5b3173248284f4c6ce0af628f2f140cd
4
- data.tar.gz: 447a2c03a49e23e2ba1750d05922b84e95df7bebfd5dbeacc3331cefa6882b8e
3
+ metadata.gz: f29b35b5b6dadfd9638907704a3bc204ebd35ba3c7e95c4bfafb0ff7ed1f44ed
4
+ data.tar.gz: e6e005f4dc472961daaa02f094c8d044a76018628a0e7d07ea6ed55ab0d830b6
5
5
  SHA512:
6
- metadata.gz: d8bd44b19b45e5482d141520c84589a08b646bfa2691b48d233e2c844745d1084081e16e23971a71f71bda796c85c3e6a599be33bbf839b2bc2d8d626b8a3cf1
7
- data.tar.gz: 2600e70853d9d590075c3c172e3bea65a75795d0a667ab4dffa8361c6bc3a4d829643ac64eac42f2fb260639759326ab5af00d36cda2538634f4d0656ca94628
6
+ metadata.gz: 0bd8988be66a9514cc80732a5d66b52fc737f44f67b1949271230fbb083e3a8fcc95a515b1bc5fd2688b51449cc04e5e162c70f66de14531075f4f6606bd2002
7
+ data.tar.gz: 5aa8a44f9dc5bd935b380ab59654e2e382726a977ea404ebe8c20401df29536425f50619857ae87a6b3ee4674377b83fa3a211b73fc232bc2ff1ce7af61df128
@@ -1,3 +1,6 @@
1
+ ## [1.0.11]
2
+ - Fix: load prompt_file for main instance in orchestrator: https://github.com/parruda/swarm/pull/183
3
+
1
4
  ## [1.0.10]
2
5
 
3
6
  ### Changed
data/CLAUDE.md CHANGED
@@ -146,7 +146,6 @@ swarm = SwarmSDK.load_file("swarm.yml")
146
146
  - **MemoryWrite** - Create/update memory entries with semantic indexing
147
147
  - **MemoryRead** - Retrieve memory entries with optional semantic search
148
148
  - **MemoryEdit** - Edit specific memory entries
149
- - **MemoryMultiEdit** - Batch edit multiple entries
150
149
  - **MemoryDelete** - Remove memory entries
151
150
  - **MemoryGrep** - Search memory content with regex
152
151
  - **MemoryGlob** - Find memory entries by pattern
@@ -0,0 +1,172 @@
1
+ # Decision: Global Agent Registry for SwarmSDK
2
+
3
+ **Date:** 2025-11-22
4
+ **Status:** Implemented
5
+
6
+ ## Context
7
+
8
+ Users wanted the ability to declare agents in separate files and reference them by name in swarm definitions. This promotes:
9
+ - Code reuse across multiple swarms
10
+ - Separation of concerns (agent definitions vs swarm composition)
11
+ - Cleaner organization for large projects
12
+
13
+ ## Decision
14
+
15
+ Implement a global `AgentRegistry` that stores agent configuration blocks and allows referencing them in `SwarmSDK.build` and `SwarmSDK.workflow` definitions.
16
+
17
+ ### API Design
18
+
19
+ ```ruby
20
+ # Register agent in separate file (e.g., agents/backend.rb)
21
+ SwarmSDK.agent :backend do
22
+ model "claude-sonnet-4"
23
+ description "Backend developer"
24
+ system_prompt "You build APIs"
25
+ tools :Read, :Edit, :Bash
26
+ end
27
+
28
+ # Reference in swarm definition
29
+ SwarmSDK.build do
30
+ name "Dev Team"
31
+ lead :backend
32
+
33
+ agent :backend # Lookup from registry
34
+ end
35
+
36
+ # Extend with overrides
37
+ SwarmSDK.build do
38
+ name "Extended Team"
39
+ lead :backend
40
+
41
+ agent :backend do
42
+ tools :CustomTool # Adds to registry tools
43
+ end
44
+ end
45
+ ```
46
+
47
+ ### Key Design Decisions
48
+
49
+ 1. **Proc Storage (not Lambda)**
50
+ - Procs work naturally with `instance_eval` DSL semantics
51
+ - Flexible arity handling suits DSL blocks
52
+ - Blocks passed to methods are already Procs
53
+
54
+ 2. **Class with Class Methods (not Singleton)**
55
+ - Simpler than full Singleton pattern
56
+ - Easier to test with `AgentRegistry.clear`
57
+ - Class methods feel natural for global registry
58
+
59
+ 3. **Duplicate Registration Error**
60
+ - Raises `ArgumentError` if registering same name twice
61
+ - Prevents accidental overwrites across files
62
+ - User must call `SwarmSDK.clear_agent_registry!` to reset
63
+
64
+ 4. **Registry Takes Precedence**
65
+ - When `agent :name do ... end` is called and agent is registered:
66
+ - Registry config is applied first
67
+ - Block becomes overrides (additive)
68
+ - Promotes DRY principle - registry is source of truth
69
+
70
+ 5. **No Thread Safety**
71
+ - SwarmSDK uses fiber-based concurrency (Async gem)
72
+ - Single-threaded execution means no race conditions
73
+ - Documented limitation for multi-threaded environments
74
+
75
+ 6. **Delegation is Swarm-Specific (Best Practice)**
76
+ - Don't set `delegates_to` in registry agent definitions
77
+ - Delegation targets depend on which agents exist in each swarm
78
+ - Set `delegates_to` as an override when referencing the agent in a swarm
79
+ - This makes agents truly reusable across different swarm compositions
80
+
81
+ ## Implementation
82
+
83
+ ### New Files
84
+ - `lib/swarm_sdk/agent_registry.rb` - AgentRegistry class
85
+
86
+ ### Modified Files
87
+ - `lib/swarm_sdk.rb` - Added `SwarmSDK.agent` and `SwarmSDK.clear_agent_registry!`
88
+ - `lib/swarm_sdk/builders/base_builder.rb` - Added registry lookup to `#agent` method
89
+
90
+ ### Test Coverage
91
+ - 26 tests covering:
92
+ - Registry class methods (register, get, registered?, names, clear)
93
+ - Module methods (agent, clear_agent_registry!)
94
+ - Registry lookup in Swarm and Workflow builders
95
+ - Registry + overrides behavior
96
+ - Multiple swarms sharing registry
97
+ - Error handling
98
+ - Edge cases
99
+
100
+ ## Alternatives Considered
101
+
102
+ 1. **Explicit Syntax (`agent :name, from: :registry`)**
103
+ - Rejected: Too verbose for common use case
104
+ - Current behavior is intuitive (no args = lookup)
105
+
106
+ 2. **Warning on Shadow**
107
+ - Rejected: Too noisy, users might ignore
108
+ - Error-free operation preferred
109
+
110
+ 3. **Thread-Safe Implementation**
111
+ - Rejected: Unnecessary complexity for fiber-based model
112
+ - The definitions should be eager loaded in the app that is using the SDK
113
+ - Documented limitation acceptable
114
+
115
+ ## Enhancement: Workflow Node Registry Fallback
116
+
117
+ Added automatic agent resolution in workflow nodes. When `agent(:name)` is called inside a node:
118
+
119
+ 1. First checks if agent is defined at workflow level
120
+ 2. If not found, checks the global AgentRegistry
121
+ 3. If still not found, raises ConfigurationError
122
+
123
+ This allows powerful patterns like:
124
+
125
+ ```ruby
126
+ # agents/shared.rb
127
+ SwarmSDK.agent :shared_analyzer do
128
+ model "claude-sonnet-4"
129
+ description "Shared analyzer"
130
+ end
131
+
132
+ # workflow.rb
133
+ SwarmSDK.workflow do
134
+ name "Pipeline"
135
+ start_node :analyze
136
+
137
+ # No need to define shared_analyzer here!
138
+
139
+ node :analyze do
140
+ agent(:shared_analyzer) # Auto-resolved from registry
141
+ end
142
+ end
143
+ ```
144
+
145
+ The fallback also resolves delegation targets:
146
+
147
+ ```ruby
148
+ node :process do
149
+ agent(:main_agent).delegates_to(:helper_agent)
150
+ # Both resolved from registry
151
+ end
152
+ ```
153
+
154
+ ### Implementation
155
+ - Modified `Workflow::Builder#build_workflow` to call `resolve_missing_agents_from_registry`
156
+ - Added `collect_referenced_agents` to gather all agents from nodes (including delegates_to)
157
+ - Resolution happens at build time before agent definitions are built
158
+
159
+ ## Consequences
160
+
161
+ ### Positive
162
+ - Clean separation of agent definitions from swarm composition
163
+ - Easy code reuse across swarms
164
+ - Intuitive API that matches existing DSL patterns
165
+ - Works with both Swarm and Workflow builders
166
+ - Workflow nodes automatically resolve agents from registry
167
+ - Delegation targets also auto-resolve from registry
168
+
169
+ ### Negative
170
+ - Global state (mitigated by clear method for testing)
171
+ - Not thread-safe (documented limitation)
172
+ - Must require agent files before building swarms
@@ -5,6 +5,18 @@ All notable changes to SwarmCLI will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.1.7]
9
+
10
+ ### Dependencies
11
+
12
+ - Updated `swarm_sdk` to `~> 2.5.1`
13
+
14
+ ## [2.1.6]
15
+ - Bump SDK and memory gem versions
16
+
17
+ ## [2.1.5]
18
+ - Bump SDK gem version
19
+
8
20
  ## [2.1.4]
9
21
 
10
22
  ### Changed
@@ -5,6 +5,145 @@ All notable changes to SwarmMemory will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.2.3]
9
+
10
+ ### Fixed
11
+
12
+ - **Hybrid search weight configuration**: Fixed bug where `semantic_weight` and `keyword_weight` from config weren't being passed to SemanticIndex
13
+ - **Issue**: SDK plugin extracted weights from config but didn't pass them to Storage/SemanticIndex
14
+ - **Fix**: Storage now accepts and passes weight parameters through to SemanticIndex
15
+ - **Impact**: Per-agent weight configuration now works correctly (was only used for logging before)
16
+ - **Files**: `lib/swarm_memory/core/storage.rb:23-35`, `lib/swarm_memory/integration/sdk_plugin.rb:130-150`
17
+
18
+ - **YAML config with string keys**: Fixed bug where Hash configs with string keys would fail adapter initialization
19
+ - **Issue**: Adapters expect symbol keyword arguments, but YAML configs have string keys
20
+ - **Fix**: Symbolize adapter option keys in create_storage for Hash configs
21
+ - **Impact**: YAML configurations now work correctly with all adapters
22
+ - **Files**: `lib/swarm_memory/integration/sdk_plugin.rb:113-118`
23
+
24
+ ### Added
25
+
26
+ - **DSL methods for weights**: Added `semantic_weight()` and `keyword_weight()` methods to MemoryConfig
27
+ - **Before**: `option(:semantic_weight, 0.8)`
28
+ - **After**: `semantic_weight(0.8)` (cleaner syntax, consistent with `directory()` and `mode()`)
29
+ - **Backward compatible**: `option()` method still works
30
+ - **Files**: `lib/swarm_memory/dsl/memory_config.rb:87-122`
31
+
32
+ ### Changed
33
+
34
+ - **Automatic semantic fallback**: Hybrid search now falls back to pure semantic scoring when keyword_score is 0
35
+ - **Before**: semantic=0.92, keyword=0.0 → final=0.46 (penalized by 50/50 weights)
36
+ - **After**: semantic=0.92, keyword=0.0 → final=0.92 (no penalty when no tag matches)
37
+ - **Rationale**: Prevents excellent semantic matches from being penalized when there's no keyword/tag overlap
38
+ - **Impact**: Improved recall for queries with no tag matches
39
+ - **Files**: `lib/swarm_memory/core/semantic_index.rb:195-201`
40
+
41
+ ## [2.2.2]
42
+
43
+ ### Dependencies
44
+
45
+ - Updated `swarm_sdk` to `~> 2.5.1`
46
+
47
+ ## [2.2.1]
48
+
49
+ ### Fixed
50
+
51
+ - **MemoryEdit metadata preservation**: MemoryEdit now preserves all metadata when updating entry content
52
+ - **Issue**: MemoryEdit was only preserving title, losing tags, confidence, domain, and other metadata
53
+ - **Fix**: Pass `metadata: entry.metadata` to storage.write to preserve all existing metadata
54
+ - **Impact**: Prevents metadata loss when editing memory entries
55
+ - **Files**: `lib/swarm_memory/tools/memory_edit.rb:169`
56
+
57
+ ## [2.2.0]
58
+
59
+ ### Added
60
+
61
+ - **Per-Adapter Threshold Configuration**: Semantic search thresholds can now be configured per-adapter in YAML
62
+ - **Fallback chain**: `adapter_config → ENV var → hardcoded_default` (config wins over ENV)
63
+ - **Supported threshold keys**:
64
+ - `discovery_threshold` (default: 0.35) - Main similarity threshold for normal queries
65
+ - `discovery_threshold_short` (default: 0.25) - Threshold for queries with <10 words
66
+ - `adaptive_word_cutoff` (default: 10) - Word count to switch between thresholds
67
+ - `semantic_weight` (default: 0.5) - Hybrid search semantic weight
68
+ - `keyword_weight` (default: 0.5) - Hybrid search keyword weight
69
+ - **Use cases**: Per-agent threshold tuning, adapter-specific optimization (pgvector vs FAISS), multi-tenant customization
70
+ - **Backward compatible**: ENV vars still work as deployment-level override
71
+ - **Zero config required**: Sensible defaults work out of the box
72
+ - **Example**:
73
+ ```yaml
74
+ memory:
75
+ adapter: multi_bank_postgres
76
+ agent_id: researcher
77
+ discovery_threshold: 0.5
78
+ discovery_threshold_short: 0.3
79
+ semantic_weight: 0.6
80
+ ```
81
+ - **Files**: `lib/swarm_memory/integration/sdk_plugin.rb`
82
+ - **Tests**: 4 new tests validating threshold extraction and fallback behavior
83
+
84
+ - **Custom Adapter Support**: SwarmMemory now fully supports custom storage adapters
85
+ - **Custom adapter options pass-through**: All YAML config keys (except `directory`, `adapter`, `mode`) are now passed to adapter constructor
86
+ - **Example configuration**:
87
+ ```yaml
88
+ memory:
89
+ adapter: multi_bank_postgres
90
+ agent_id: business_consultant
91
+ default_bank: working
92
+ banks:
93
+ working: { max_size: 10485760 }
94
+ long_term: { max_size: 52428800 }
95
+ bank_access:
96
+ archive: read_only
97
+ ```
98
+ - **Enables**: PostgreSQL, MySQL, Redis, S3, and any custom storage backend
99
+ - **Files**: `lib/swarm_memory/integration/sdk_plugin.rb:290-310`
100
+ - **Tests**: 2 new tests for custom adapter option pass-through
101
+
102
+ ### Changed
103
+
104
+ - **BREAKING: `storage_enabled?` renamed to `memory_configured?`** in SDKPlugin
105
+ - **Improved logic**: Filesystem adapter requires `directory`, custom adapters can use any configuration keys
106
+ - **Better validation**: Custom adapters are recognized as valid even without `directory` key
107
+ - **Adapter validation**: Each adapter validates its own requirements during initialization
108
+ - **No backward compatibility**: `storage_enabled?` method removed entirely (breaking change)
109
+ - **Migration**: Update any code calling `plugin.storage_enabled?()` to use `plugin.memory_configured?()`
110
+ - **Files**: `lib/swarm_memory/integration/sdk_plugin.rb:202-235`
111
+ - **Tests**: 3 new tests for custom adapter recognition
112
+
113
+ ### Removed
114
+
115
+ - **MemoryMultiEdit tool**: Removed in favor of simpler MemoryEdit tool
116
+ - **Rationale**: Memory entries are small (typically < 100 lines), making batch edits unnecessary
117
+ - **Alternative**: Use multiple `MemoryEdit` calls for sequential edits
118
+ - **Simplification**: Reduces API complexity and LLM error surface (JSON parameter was error-prone)
119
+ - **Files removed**: `lib/swarm_memory/tools/memory_multi_edit.rb`
120
+ - **Tool count**: Memory tools reduced from 8 to 7 (MemoryWrite, MemoryRead, MemoryEdit, MemoryDelete, MemoryGlob, MemoryGrep, MemoryDefrag)
121
+
122
+ ### Benefits
123
+
124
+ - ✅ **Eliminates need for monkey patches** when building custom adapters
125
+ - ✅ **Makes SwarmMemory fully extensible** for any storage backend
126
+ - ✅ **Per-agent threshold tuning** for optimal semantic search accuracy
127
+ - ✅ **Multi-tenant customization** with per-adapter configuration
128
+ - ✅ **Clearer semantics** (memory vs storage terminology)
129
+ - ✅ **Better error messages** (adapters validate themselves)
130
+
131
+ ## [2.1.7]
132
+
133
+ ### Dependencies
134
+
135
+ - Updated `ruby_llm_swarm` to `~> 1.9.5`
136
+
137
+ ## [2.1.6]
138
+ - Fix files included in the gem
139
+
140
+ ## [2.1.5]
141
+
142
+ ### Fixed
143
+ - **Fixed Zeitwerk naming convention**: Renamed `lib/swarm_memory/errors.rb` to `lib/swarm_memory/error.rb` to match the `SwarmMemory::Error` constant it defines
144
+ - Fixes `Zeitwerk::Loader.eager_load_all` failures with "uninitialized constant SwarmMemory::Errors" errors
145
+ - Properly follows Zeitwerk file naming conventions where `error.rb` defines `Error` class
146
+
8
147
  ## [2.1.4]
9
148
 
10
149
  ### Changed
@@ -5,6 +5,254 @@ All notable changes to SwarmSDK will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.5.1]
9
+
10
+ ### Dependencies
11
+
12
+ - Updated `ruby_llm_swarm-mcp` to `~> 0.8.1`
13
+
14
+ ## [2.5.0]
15
+
16
+ ### Added
17
+
18
+ - **Custom Tool Registration**: Simple API for registering custom tools without creating full plugins
19
+ - **`SwarmSDK.register_tool(ToolClass)`**: Register with inferred name (e.g., `WeatherTool` → `:Weather`)
20
+ - **`SwarmSDK.register_tool(:Name, ToolClass)`**: Register with explicit name
21
+ - **`SwarmSDK.custom_tool_registered?(:Name)`**: Check if tool is registered
22
+ - **`SwarmSDK.custom_tools`**: List all registered custom tool names
23
+ - **`SwarmSDK.unregister_tool(:Name)`**: Remove a registered tool
24
+ - **`SwarmSDK.clear_custom_tools!`**: Clear all registered tools (useful for testing)
25
+ - **Tool lookup order**: Plugin tools → Custom tools → Built-in tools
26
+ - **Context support**: Tools can declare `creation_requirements` for agent context (`:agent_name`, `:directory`)
27
+ - **Name consistency**: `NamedToolWrapper` ensures registered name is used for tool lookup
28
+ - **Validation**: Prevents overriding built-in tools or plugin tools
29
+ - **Use case**: Simple, stateless tools that don't need plugin lifecycle hooks or storage
30
+ - **Example**:
31
+ ```ruby
32
+ class WeatherTool < RubyLLM::Tool
33
+ description "Get weather for a city"
34
+ param :city, type: "string", required: true
35
+
36
+ def execute(city:)
37
+ "Weather in #{city}: Sunny"
38
+ end
39
+ end
40
+
41
+ SwarmSDK.register_tool(WeatherTool)
42
+
43
+ SwarmSDK.build do
44
+ name "Assistant"
45
+ lead :helper
46
+
47
+ agent :helper do
48
+ model "claude-sonnet-4"
49
+ description "Weather assistant"
50
+ system_prompt "You help with weather"
51
+ tools :Weather # Use the registered tool
52
+ end
53
+ end
54
+ ```
55
+ - **Files**: `lib/swarm_sdk/custom_tool_registry.rb`, `lib/swarm_sdk.rb`, `lib/swarm_sdk/swarm/tool_configurator.rb`
56
+ - **Tests**: 32 comprehensive tests (unit + integration)
57
+
58
+ ### Changed
59
+
60
+ - **BREAKING: Plugin API method renamed**: `storage_enabled?` → `memory_configured?` in Plugin base class
61
+ - **Rationale**: "memory" is the user-facing concept, "storage" is internal implementation detail
62
+ - **Better semantics**: "Is memory configured?" vs "Is storage enabled?"
63
+ - **No backward compatibility**: `storage_enabled?` method removed entirely (breaking change)
64
+ - **Impact**: Custom plugins implementing `storage_enabled?` must rename to `memory_configured?`
65
+ - **Migration**: Update plugin classes to implement `memory_configured?` instead of `storage_enabled?`
66
+ - **Files**: `lib/swarm_sdk/plugin.rb:142-148`
67
+ - **Updated callers**:
68
+ - `lib/swarm_sdk/swarm/agent_initializer.rb:572`
69
+ - `lib/swarm_sdk/agent/system_prompt_builder.rb:151`
70
+ - `lib/swarm_sdk/swarm/tool_configurator.rb:270`
71
+ - **Tests**: All plugin-related tests updated
72
+
73
+ ## [2.4.6]
74
+ - Use a fork of ruby_llm-mcp that requires ruby_llm_swarm instead of ruby_llm
75
+
76
+ ## [2.4.5]
77
+
78
+ ### Fixed
79
+
80
+ - **Context Window Tracking Bug**: Fixed model lookup using wrong source for context window data
81
+ - **Issue**: Changes to `models.json` had no effect on context window tracking - SDK always returned 0%
82
+ - **Root cause**: `fetch_real_model_info` was using `RubyLLM.models.find()` instead of `SwarmSDK::Models.find()`
83
+ - **Fix**: Changed model lookup to use `SwarmSDK::Models.find()` first, falling back to `RubyLLM.models.find()`
84
+ - **Impact**: Context window percentage now correctly calculated from SwarmSDK's models.json
85
+ - **Files**: `lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb`
86
+
87
+ ### Added
88
+
89
+ - **Per-Agent Context Breakdown**: Real-time and historical context usage metrics per agent
90
+ - **`Swarm#context_breakdown`**: Returns live context metrics for all agents including:
91
+ - Token counts: `input_tokens`, `output_tokens`, `total_tokens`, `cached_tokens`, `cache_creation_tokens`, `effective_input_tokens`
92
+ - Context limits: `context_limit`, `usage_percentage`, `tokens_remaining`
93
+ - Cost metrics: `input_cost`, `output_cost`, `total_cost`
94
+ - **`Result#per_agent_usage`**: Extracts per-agent usage from execution logs (for historical analysis)
95
+ - **`swarm_stop` event enhancement**: Now includes `per_agent_usage` field with complete breakdown
96
+ - **Use cases**: Monitor token consumption, track costs per agent, identify context-heavy agents
97
+ - **Example**:
98
+ ```ruby
99
+ breakdown = swarm.context_breakdown
100
+ breakdown[:backend]
101
+ # => {
102
+ # input_tokens: 15000,
103
+ # output_tokens: 5000,
104
+ # total_tokens: 20000,
105
+ # cached_tokens: 2000,
106
+ # context_limit: 200000,
107
+ # usage_percentage: 10.0,
108
+ # tokens_remaining: 180000,
109
+ # input_cost: 0.045,
110
+ # output_cost: 0.075,
111
+ # total_cost: 0.12
112
+ # }
113
+ ```
114
+ - **Files**: `lib/swarm_sdk/swarm.rb`, `lib/swarm_sdk/result.rb`, `lib/swarm_sdk/swarm/hook_triggers.rb`, `lib/swarm_sdk/swarm/logging_callbacks.rb`
115
+
116
+ - **Cumulative Cost Tracking in TokenTracking**: New methods for calculating conversation costs
117
+ - **`cumulative_input_cost`**: Calculate total input cost based on tokens and model pricing
118
+ - **`cumulative_output_cost`**: Calculate total output cost based on tokens and model pricing
119
+ - **`cumulative_total_cost`**: Sum of input and output costs
120
+ - **Pricing source**: Uses `@real_model_info.pricing` from SwarmSDK's models.json
121
+ - **Files**: `lib/swarm_sdk/agent/chat_helpers/token_tracking.rb`
122
+
123
+ - **ModelInfo Class**: Wrapper class for model data with method access
124
+ - **`SwarmSDK::Models::ModelInfo`**: Replaces raw Hash returns from `Models.find()`
125
+ - **Attributes**: `id`, `name`, `provider`, `family`, `context_window`, `max_output_tokens`, `knowledge_cutoff`, `modalities`, `capabilities`, `pricing`, `metadata`
126
+ - **Files**: `lib/swarm_sdk/models.rb`
127
+
128
+ ### Tests
129
+
130
+ - **28 new tests** covering:
131
+ - `TokenTracking` cost methods (24 tests): context_limit, cumulative costs, pricing edge cases
132
+ - `Swarm#context_breakdown` (5 tests): structure, metrics, delegation instances, lazy initialization
133
+
134
+ ## [2.4.4]
135
+
136
+ ### Added
137
+
138
+ - **Environment Variable Interpolation Control**: New `env_interpolation` setting to disable YAML variable interpolation
139
+ - **Global config**: `SwarmSDK.configure { |c| c.env_interpolation = false }`
140
+ - **Environment variable**: `SWARM_SDK_ENV_INTERPOLATION=false`
141
+ - **Per-load override**: `SwarmSDK.load(yaml, env_interpolation: false)` or `SwarmSDK.load_file(path, env_interpolation: false)`
142
+ - **Priority order**: per-load parameter > global config > environment variable > default (true)
143
+ - **Use cases**:
144
+ - Testing YAML files without setting environment variables
145
+ - Loading configs where `${...}` syntax should be preserved literally
146
+ - Security: preventing accidental environment variable exposure
147
+ - **Example**:
148
+ ```ruby
149
+ # Disable globally
150
+ SwarmSDK.configure do |config|
151
+ config.env_interpolation = false
152
+ end
153
+
154
+ # Disable for specific load
155
+ swarm = SwarmSDK.load_file("config.yml", env_interpolation: false)
156
+ ```
157
+ - **Files**: `lib/swarm_sdk/config.rb`, `lib/swarm_sdk/configuration.rb`, `lib/swarm_sdk/configuration/parser.rb`, `lib/swarm_sdk.rb`
158
+ - **Tests**: Comprehensive tests in `config_test.rb` and `configuration_test.rb`
159
+
160
+ ## [2.4.3]
161
+
162
+ ### Added
163
+
164
+ - **Global Agent Registry**: Declare agents in separate files and reference them by name across swarms
165
+ - **`SwarmSDK.agent(:name) { ... }`**: Register agents globally for reuse across multiple swarms
166
+ - **`SwarmSDK.clear_agent_registry!`**: Clear all registrations (useful for testing)
167
+ - **Registry lookup in builders**: `agent :name` (no block) fetches from global registry
168
+ - **Registry + overrides**: `agent :name do ... end` applies registry config then override block
169
+ - **Duplicate registration error**: Raises `ArgumentError` if registering same name twice
170
+ - **Workflow node auto-resolution**: Agents referenced in nodes automatically resolve from registry
171
+ - Checks workflow-level definitions first, then falls back to global registry
172
+ - Includes delegation targets (`delegates_to`) in auto-resolution
173
+ - **Best practice**: Don't set `delegates_to` in registry—delegation is swarm-specific. Set it as an override in each swarm.
174
+ - **Use case**: Define agents once in separate files, compose into multiple swarms without duplication
175
+ - **Example**:
176
+ ```ruby
177
+ # agents/backend.rb
178
+ SwarmSDK.agent :backend do
179
+ model "claude-sonnet-4"
180
+ description "Backend developer"
181
+ tools :Read, :Edit, :Bash
182
+ end
183
+
184
+ # swarm.rb
185
+ SwarmSDK.build do
186
+ name "Dev Team"
187
+ lead :backend
188
+ agent :backend # Pulls from registry
189
+ end
190
+
191
+ # workflow.rb - agents auto-resolve in nodes
192
+ SwarmSDK.workflow do
193
+ name "Pipeline"
194
+ start_node :build
195
+ node(:build) { agent(:backend) } # Auto-resolved from registry
196
+ end
197
+ ```
198
+ - **Files**: `lib/swarm_sdk/agent_registry.rb`, `lib/swarm_sdk.rb`, `lib/swarm_sdk/builders/base_builder.rb`, `lib/swarm_sdk/workflow/builder.rb`
199
+ - **Tests**: 32 comprehensive tests in `test/swarm_sdk/agent_registry_test.rb`
200
+
201
+ ## [2.4.2]
202
+
203
+ ### Fixed
204
+
205
+ - **Duplicate event emission bug**: Fixed agent_stop and agent_step events being emitted twice
206
+ - Root cause: `setup_logging` was being called twice during agent initialization
207
+ - First call in `agent_initializer.rb` when `LogStream.emitter` was set
208
+ - Second call in `emit_retroactive_agent_start_events` via `setup_logging_for_all_agents`
209
+ - Fix: Made `ContextTracker#setup_logging` idempotent with `@logging_setup` guard
210
+ - Prevents duplicate callback registration on `on_end_message`, `on_tool_result`, and `on_tool_call`
211
+
212
+ ### Added
213
+
214
+ - **Event deduplication tests**: Comprehensive test suite to prevent regression
215
+ - `test_agent_stop_event_not_duplicated` - Ensures agent_stop emitted exactly once
216
+ - `test_agent_step_event_not_duplicated` - Ensures agent_step emitted exactly once per tool response
217
+ - `test_tool_call_event_not_duplicated` - Ensures tool_call emitted exactly once per invocation
218
+ - `test_tool_result_event_not_duplicated` - Ensures tool_result emitted exactly once
219
+ - `test_setup_logging_idempotency` - Verifies idempotent behavior across multiple executions
220
+ - `test_comprehensive_event_counts_*` - Validates exact event counts for various scenarios
221
+
222
+ ### Dependencies
223
+
224
+ - Updated `ruby_llm_swarm` to `~> 1.9.5`
225
+ - Added `openssl` (`~> 3.3.2`) dependency
226
+
227
+ ## [2.4.1]
228
+ - Fix gemspec issues
229
+
230
+ ## [2.4.0]
231
+
232
+ ### Breaking Changes
233
+
234
+ - **Centralized Configuration System**: Unified all configuration into `SwarmSDK::Config`
235
+ - **New API**: `SwarmSDK.config` replaces `SwarmSDK.settings`
236
+ - **Removed**: `SwarmSDK::Settings` class removed entirely
237
+ - **Removed**: `SwarmSDK.settings` method removed
238
+ - **Removed**: `SwarmSDK.reset_settings!` → use `SwarmSDK.reset_config!`
239
+ - **Removed**: Tool constants (DEFAULT_TIMEOUT_MS, MAX_OUTPUT_LENGTH, etc.)
240
+ - **API key proxying**: All API keys automatically proxy to `RubyLLM.config`
241
+ - **Override all defaults**: Every constant in Defaults module can now be overridden at runtime
242
+ - **Priority**: explicit value → ENV variable → Defaults module constant
243
+ - **Lazy ENV loading**: Thread-safe with double-check locking
244
+ - **Migration**:
245
+ - `SwarmSDK.settings.allow_filesystem_tools` → `SwarmSDK.config.allow_filesystem_tools`
246
+ - `SwarmSDK.reset_settings!` → `SwarmSDK.reset_config!`
247
+ - Tool constants → `SwarmSDK.config.*` methods (e.g., `SwarmSDK.config.bash_command_timeout`)
248
+
249
+ ### Fixed
250
+
251
+ - **Base URL Configuration Bug**: Custom provider contexts now properly use configured API keys
252
+ - Previously: `configure_provider_base_url` read ENV directly, ignoring `RubyLLM.config`
253
+ - Now: Uses `SwarmSDK.config.openai_api_key` and other configured values
254
+ - Better error messages when API keys are missing for non-local endpoints
255
+
8
256
  ## [2.3.0]
9
257
 
10
258
  ### Breaking Changes
@@ -271,7 +519,7 @@ old[:metadata] = old.delete(:swarm)
271
519
  - **Documentation**: Complete guide in `docs/v2/guides/snapshots.md` with examples and comparisons
272
520
 
273
521
  - **System-Wide Filesystem Tools Control**: Global security setting to disable filesystem tools across all agents
274
- - **`SwarmSDK.settings.allow_filesystem_tools`** - Global setting to enable/disable filesystem tools (default: true)
522
+ - **`SwarmSDK.config.allow_filesystem_tools`** - Global setting to enable/disable filesystem tools (default: true)
275
523
  - **Environment variable**: `SWARM_SDK_ALLOW_FILESYSTEM_TOOLS` - Set via environment for production deployments
276
524
  - **Parameter override**: `allow_filesystem_tools:` parameter in `SwarmSDK.build`, `load`, and `load_file`
277
525
  - **Filesystem tools**: Read, Write, Edit, MultiEdit, Grep, Glob, Bash