swarm_memory 2.1.5 → 2.1.6

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. metadata +5 -184
  4. data/lib/claude_swarm/base_executor.rb +0 -133
  5. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  6. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  7. data/lib/claude_swarm/cli.rb +0 -697
  8. data/lib/claude_swarm/commands/ps.rb +0 -215
  9. data/lib/claude_swarm/commands/show.rb +0 -139
  10. data/lib/claude_swarm/configuration.rb +0 -373
  11. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  12. data/lib/claude_swarm/json_handler.rb +0 -91
  13. data/lib/claude_swarm/mcp_generator.rb +0 -230
  14. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  15. data/lib/claude_swarm/openai/executor.rb +0 -256
  16. data/lib/claude_swarm/openai/responses.rb +0 -319
  17. data/lib/claude_swarm/orchestrator.rb +0 -878
  18. data/lib/claude_swarm/process_tracker.rb +0 -78
  19. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  20. data/lib/claude_swarm/session_path.rb +0 -42
  21. data/lib/claude_swarm/settings_generator.rb +0 -77
  22. data/lib/claude_swarm/system_utils.rb +0 -46
  23. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  24. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  25. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  27. data/lib/claude_swarm/version.rb +0 -5
  28. data/lib/claude_swarm/worktree_manager.rb +0 -475
  29. data/lib/claude_swarm/yaml_loader.rb +0 -22
  30. data/lib/claude_swarm.rb +0 -67
  31. data/lib/swarm_cli/cli.rb +0 -201
  32. data/lib/swarm_cli/command_registry.rb +0 -61
  33. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  34. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  35. data/lib/swarm_cli/commands/migrate.rb +0 -55
  36. data/lib/swarm_cli/commands/run.rb +0 -173
  37. data/lib/swarm_cli/config_loader.rb +0 -98
  38. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  39. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  40. data/lib/swarm_cli/interactive_repl.rb +0 -924
  41. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  42. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  43. data/lib/swarm_cli/migrate_options.rb +0 -54
  44. data/lib/swarm_cli/migrator.rb +0 -132
  45. data/lib/swarm_cli/options.rb +0 -151
  46. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  47. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  48. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  49. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  50. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  51. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  52. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  53. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  54. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  55. data/lib/swarm_cli/ui/icons.rb +0 -36
  56. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  57. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  58. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  59. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  60. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  61. data/lib/swarm_cli/version.rb +0 -5
  62. data/lib/swarm_cli.rb +0 -46
  63. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  64. data/lib/swarm_sdk/agent/builder.rb +0 -552
  65. data/lib/swarm_sdk/agent/chat.rb +0 -774
  66. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  67. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  68. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  69. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  70. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  71. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  72. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  73. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  75. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  76. data/lib/swarm_sdk/agent/context.rb +0 -116
  77. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  78. data/lib/swarm_sdk/agent/definition.rb +0 -477
  79. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  80. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  81. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  82. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  83. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  84. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  85. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  86. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  87. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  88. data/lib/swarm_sdk/configuration.rb +0 -135
  89. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  90. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  91. data/lib/swarm_sdk/context_compactor.rb +0 -335
  92. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  93. data/lib/swarm_sdk/context_management/context.rb +0 -328
  94. data/lib/swarm_sdk/defaults.rb +0 -196
  95. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  96. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  97. data/lib/swarm_sdk/hooks/context.rb +0 -197
  98. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  99. data/lib/swarm_sdk/hooks/error.rb +0 -29
  100. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  101. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  102. data/lib/swarm_sdk/hooks/result.rb +0 -150
  103. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  104. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  105. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  106. data/lib/swarm_sdk/log_collector.rb +0 -227
  107. data/lib/swarm_sdk/log_stream.rb +0 -127
  108. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  109. data/lib/swarm_sdk/model_aliases.json +0 -8
  110. data/lib/swarm_sdk/models.json +0 -1
  111. data/lib/swarm_sdk/models.rb +0 -120
  112. data/lib/swarm_sdk/node_context.rb +0 -245
  113. data/lib/swarm_sdk/observer/builder.rb +0 -81
  114. data/lib/swarm_sdk/observer/config.rb +0 -45
  115. data/lib/swarm_sdk/observer/manager.rb +0 -236
  116. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  117. data/lib/swarm_sdk/permissions/config.rb +0 -239
  118. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  119. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  120. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  121. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  122. data/lib/swarm_sdk/plugin.rb +0 -309
  123. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  124. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  125. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  126. data/lib/swarm_sdk/restore_result.rb +0 -65
  127. data/lib/swarm_sdk/result.rb +0 -123
  128. data/lib/swarm_sdk/snapshot.rb +0 -156
  129. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  130. data/lib/swarm_sdk/state_restorer.rb +0 -476
  131. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  132. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  133. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  134. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  135. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  136. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  141. data/lib/swarm_sdk/swarm.rb +0 -717
  142. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  143. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  144. data/lib/swarm_sdk/tools/bash.rb +0 -282
  145. data/lib/swarm_sdk/tools/clock.rb +0 -44
  146. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  147. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  148. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  149. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  150. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  151. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  152. data/lib/swarm_sdk/tools/edit.rb +0 -145
  153. data/lib/swarm_sdk/tools/glob.rb +0 -166
  154. data/lib/swarm_sdk/tools/grep.rb +0 -235
  155. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  156. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  157. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  158. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  159. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  160. data/lib/swarm_sdk/tools/read.rb +0 -261
  161. data/lib/swarm_sdk/tools/registry.rb +0 -205
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  165. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  166. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  167. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  168. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  169. data/lib/swarm_sdk/tools/think.rb +0 -98
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/utils.rb +0 -68
  174. data/lib/swarm_sdk/validation_result.rb +0 -33
  175. data/lib/swarm_sdk/version.rb +0 -5
  176. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  177. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  178. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  179. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  180. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  181. data/lib/swarm_sdk/workflow.rb +0 -554
  182. data/lib/swarm_sdk.rb +0 -524
@@ -1,683 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Handles the complex 5-pass agent initialization process
6
- #
7
- # Responsibilities:
8
- # - Create all agent chat instances (pass 1)
9
- # - Register delegation tools (pass 2)
10
- # - Setup agent contexts (pass 3)
11
- # - Configure hook system (pass 4)
12
- # - Apply YAML hooks if present (pass 5)
13
- #
14
- # This encapsulates the complex initialization logic that was previously
15
- # embedded in Swarm#initialize_agents.
16
- class AgentInitializer
17
- # Initialize with swarm reference (all data accessible via swarm)
18
- #
19
- # @param swarm [Swarm] The parent swarm instance
20
- def initialize(swarm)
21
- @swarm = swarm
22
- @agents = {}
23
- @agent_contexts = {}
24
- end
25
-
26
- # Initialize all agents with their chat instances and tools
27
- #
28
- # This implements a 5-pass algorithm:
29
- # 1. Create all Agent::Chat instances
30
- # 2. Register delegation tools (agents can call each other)
31
- # 3. Setup agent contexts for tracking
32
- # 4. Configure hook system
33
- # 5. Apply YAML hooks (if loaded from YAML)
34
- #
35
- # @return [Hash] agents hash { agent_name => Agent::Chat }
36
- def initialize_all
37
- pass_1_create_agents
38
- pass_2_register_delegation_tools
39
- pass_3_setup_contexts
40
- pass_4_configure_hooks
41
- pass_5_apply_yaml_hooks
42
-
43
- @agents
44
- end
45
-
46
- # Provide access to agent contexts for Swarm
47
- attr_reader :agent_contexts
48
-
49
- # Initialize a single agent in isolation (for observer agents)
50
- #
51
- # Creates an isolated agent chat without delegation tools,
52
- # suitable for observer agents that don't need to delegate.
53
- # Reuses existing create_agent_chat infrastructure.
54
- #
55
- # @param agent_name [Symbol] Name of agent to initialize
56
- # @return [Agent::Chat] Isolated agent chat instance
57
- # @raise [ConfigurationError] If agent not found
58
- #
59
- # @example
60
- # initializer = AgentInitializer.new(swarm)
61
- # chat = initializer.initialize_isolated_agent(:profiler)
62
- # chat.ask("Analyze this prompt")
63
- def initialize_isolated_agent(agent_name)
64
- agent_def = @swarm.agent_definitions[agent_name]
65
- raise ConfigurationError, "Agent '#{agent_name}' not found" unless agent_def
66
-
67
- # Ensure plugin storages are created (needed by ToolConfigurator)
68
- create_plugin_storages if @swarm.plugin_storages.empty?
69
-
70
- # Reuse existing create_agent_chat infrastructure
71
- tool_configurator = ToolConfigurator.new(
72
- @swarm,
73
- @swarm.scratchpad_storage,
74
- @swarm.plugin_storages,
75
- )
76
-
77
- # Create chat using same method as pass_1_create_agents
78
- # This gives us full tool setup, MCP servers, etc.
79
- create_agent_chat(agent_name, agent_def, tool_configurator)
80
- end
81
-
82
- # Create a tool that delegates work to another agent
83
- #
84
- # This method is public for testing delegation from Swarm.
85
- #
86
- # @param name [String] Delegate agent name
87
- # @param description [String] Delegate agent description
88
- # @param delegate_chat [Agent::Chat] The delegate's chat instance
89
- # @param agent_name [Symbol] Name of the delegating agent
90
- # @param delegating_chat [Agent::Chat, nil] The chat instance of the agent doing the delegating
91
- # @return [Tools::Delegate] Delegation tool
92
- def create_delegation_tool(name:, description:, delegate_chat:, agent_name:, delegating_chat: nil)
93
- Tools::Delegate.new(
94
- delegate_name: name,
95
- delegate_description: description,
96
- delegate_chat: delegate_chat,
97
- agent_name: agent_name,
98
- swarm: @swarm,
99
- delegating_chat: delegating_chat,
100
- )
101
- end
102
-
103
- private
104
-
105
- # Pass 1: Create primary agent chat instances
106
- #
107
- # Only creates agents that will actually be used as primaries:
108
- # - The lead agent
109
- # - Agents with shared_across_delegations: true (shared delegates)
110
- # - Agents not used as delegates (standalone agents)
111
- #
112
- # Agents that are ONLY delegates with shared_across_delegations: false
113
- # are NOT created here - they'll be created as delegation instances in pass 2a.
114
- def pass_1_create_agents
115
- # Create plugin storages for agents
116
- create_plugin_storages
117
-
118
- tool_configurator = ToolConfigurator.new(@swarm, @swarm.scratchpad_storage, @swarm.plugin_storages)
119
-
120
- @swarm.agent_definitions.each do |name, agent_definition|
121
- # Skip if this agent will only exist as delegation instances
122
- next if should_skip_primary_creation?(name, agent_definition)
123
-
124
- chat = create_agent_chat(name, agent_definition, tool_configurator)
125
- @agents[name] = chat
126
-
127
- # Notify plugins that agent was initialized
128
- notify_plugins_agent_initialized(name, chat, agent_definition, tool_configurator)
129
- end
130
- end
131
-
132
- # Pass 2: Create delegation instances and wire delegation tools
133
- #
134
- # This pass has three sub-steps that must happen in order:
135
- # 2a. Create delegation instances (ONLY for agents with shared_across_delegations: false)
136
- # 2b. Wire primary agents to delegation instances OR shared primaries
137
- # 2c. Wire delegation instances to their delegates (nested delegation support)
138
- def pass_2_register_delegation_tools
139
- tool_configurator = ToolConfigurator.new(@swarm, @swarm.scratchpad_storage, @swarm.plugin_storages)
140
-
141
- # Sub-pass 2a: Create delegation instances for isolated agents
142
- @swarm.agent_definitions.each do |delegator_name, delegator_def|
143
- delegator_def.delegates_to.each do |delegate_base_name|
144
- delegate_base_name = delegate_base_name.to_sym
145
-
146
- unless @swarm.agent_definitions.key?(delegate_base_name)
147
- raise ConfigurationError,
148
- "Agent '#{delegator_name}' delegates to unknown agent '#{delegate_base_name}'"
149
- end
150
-
151
- delegate_definition = @swarm.agent_definitions[delegate_base_name]
152
-
153
- # Check isolation mode of the DELEGATE agent
154
- # If delegate wants to be shared, skip instance creation (use primary)
155
- next if delegate_definition.shared_across_delegations
156
-
157
- # Create unique delegation instance (isolated mode)
158
- instance_name = "#{delegate_base_name}@#{delegator_name}"
159
-
160
- # V7.0: Use existing register_all_tools (no new method needed!)
161
- delegation_chat = create_agent_chat_for_delegation(
162
- instance_name: instance_name,
163
- base_name: delegate_base_name,
164
- agent_definition: delegate_definition,
165
- tool_configurator: tool_configurator,
166
- )
167
-
168
- # Store in delegation_instances hash
169
- @swarm.delegation_instances[instance_name] = delegation_chat
170
- end
171
- end
172
-
173
- # Sub-pass 2b: Wire primary agents to delegation instances OR shared primaries OR registered swarms
174
- @swarm.agent_definitions.each do |delegator_name, delegator_def|
175
- delegator_chat = @agents[delegator_name]
176
-
177
- # Skip if delegator doesn't exist as primary (wasn't created in pass_1)
178
- next unless delegator_chat
179
-
180
- delegator_def.delegates_to.each do |delegate_name|
181
- wire_delegation(
182
- delegator_name: delegator_name,
183
- delegator_chat: delegator_chat,
184
- delegate_name: delegate_name,
185
- tool_configurator: tool_configurator,
186
- create_nested_instances: false,
187
- )
188
- end
189
- end
190
-
191
- # Sub-pass 2c: Wire delegation instances to their delegates (nested delegation)
192
- # Convert to array first to avoid "can't add key during iteration" error
193
- @swarm.delegation_instances.to_a.each do |instance_name, delegation_chat|
194
- base_name = extract_base_name(instance_name)
195
- delegate_definition = @swarm.agent_definitions[base_name]
196
-
197
- # Register delegation tools for THIS instance's delegates_to
198
- delegate_definition.delegates_to.each do |nested_delegate_name|
199
- wire_delegation(
200
- delegator_name: instance_name.to_sym,
201
- delegator_chat: delegation_chat,
202
- delegate_name: nested_delegate_name,
203
- tool_configurator: tool_configurator,
204
- create_nested_instances: true,
205
- )
206
- end
207
- end
208
- end
209
-
210
- # Wire a single delegation from one agent/instance to a delegate
211
- #
212
- # This is the unified logic for delegation wiring used by both:
213
- # - Sub-pass 2b: Primary agents → delegates
214
- # - Sub-pass 2c: Delegation instances → nested delegates
215
- #
216
- # @param delegator_name [Symbol, String] Name of the agent doing the delegating
217
- # @param delegator_chat [Agent::Chat] Chat instance of the delegator
218
- # @param delegate_name [Symbol, String] Name of the delegate target
219
- # @param tool_configurator [ToolConfigurator] Tool configuration helper
220
- # @param create_nested_instances [Boolean] Whether to create new instances for nested delegation
221
- # @return [void]
222
- def wire_delegation(delegator_name:, delegator_chat:, delegate_name:, tool_configurator:, create_nested_instances:)
223
- delegate_name_str = delegate_name.to_s
224
- delegate_name_sym = delegate_name.to_sym
225
-
226
- # Check if target is a registered swarm
227
- if @swarm.swarm_registry&.registered?(delegate_name_str)
228
- wire_swarm_delegation(delegator_name, delegator_chat, delegate_name_str)
229
- elsif @swarm.agent_definitions.key?(delegate_name_sym)
230
- wire_agent_delegation(
231
- delegator_name: delegator_name,
232
- delegator_chat: delegator_chat,
233
- delegate_name_sym: delegate_name_sym,
234
- tool_configurator: tool_configurator,
235
- create_nested_instances: create_nested_instances,
236
- )
237
- else
238
- raise ConfigurationError,
239
- "Agent '#{delegator_name}' delegates to unknown target '#{delegate_name_str}' (not a local agent or registered swarm)"
240
- end
241
- end
242
-
243
- # Wire delegation to an external swarm
244
- #
245
- # @param delegator_name [Symbol, String] Name of the delegating agent
246
- # @param delegator_chat [Agent::Chat] Chat instance of the delegator
247
- # @param swarm_name [String] Name of the registered swarm
248
- # @return [void]
249
- def wire_swarm_delegation(delegator_name, delegator_chat, swarm_name)
250
- tool = create_delegation_tool(
251
- name: swarm_name,
252
- description: "External swarm: #{swarm_name}",
253
- delegate_chat: nil, # Swarm delegation - no direct chat
254
- agent_name: delegator_name,
255
- delegating_chat: delegator_chat,
256
- )
257
-
258
- delegator_chat.add_tool(tool)
259
- end
260
-
261
- # Wire delegation to a local agent
262
- #
263
- # Determines whether to use shared primary or isolated instance based on
264
- # the delegate's shared_across_delegations setting.
265
- #
266
- # @param delegator_name [Symbol, String] Name of the delegating agent
267
- # @param delegator_chat [Agent::Chat] Chat instance of the delegator
268
- # @param delegate_name_sym [Symbol] Name of the delegate agent
269
- # @param tool_configurator [ToolConfigurator] Tool configuration helper
270
- # @param create_nested_instances [Boolean] Whether to create new instances if not found
271
- # @return [void]
272
- def wire_agent_delegation(delegator_name:, delegator_chat:, delegate_name_sym:, tool_configurator:, create_nested_instances:)
273
- delegate_definition = @swarm.agent_definitions[delegate_name_sym]
274
-
275
- # Determine which chat instance to use
276
- target_chat = if delegate_definition.shared_across_delegations
277
- # Shared mode: use primary agent (semaphore-protected)
278
- @agents[delegate_name_sym]
279
- else
280
- # Isolated mode: use delegation instance
281
- instance_name = "#{delegate_name_sym}@#{delegator_name}"
282
-
283
- if create_nested_instances
284
- # For nested delegation: create if not exists
285
- @swarm.delegation_instances[instance_name] ||= create_agent_chat_for_delegation(
286
- instance_name: instance_name,
287
- base_name: delegate_name_sym,
288
- agent_definition: delegate_definition,
289
- tool_configurator: tool_configurator,
290
- )
291
- else
292
- # For primary delegation: instance was pre-created in 2a
293
- @swarm.delegation_instances[instance_name]
294
- end
295
- end
296
-
297
- # Create delegation tool pointing to chosen instance
298
- tool = create_delegation_tool(
299
- name: delegate_name_sym.to_s,
300
- description: delegate_definition.description,
301
- delegate_chat: target_chat,
302
- agent_name: delegator_name,
303
- delegating_chat: delegator_chat,
304
- )
305
-
306
- delegator_chat.add_tool(tool)
307
- end
308
-
309
- # Pass 3: Setup agent contexts
310
- #
311
- # Create Agent::Context for each agent to track delegations and metadata.
312
- # This is needed regardless of whether logging is enabled.
313
- def pass_3_setup_contexts
314
- # Setup contexts for PRIMARY agents
315
- @agents.each do |agent_name, chat|
316
- setup_agent_context(agent_name, @swarm.agent_definitions[agent_name], chat, is_delegation: false)
317
- end
318
-
319
- # Setup contexts for DELEGATION instances
320
- @swarm.delegation_instances.each do |instance_name, chat|
321
- base_name = extract_base_name(instance_name)
322
- agent_definition = @swarm.agent_definitions[base_name]
323
- setup_agent_context(instance_name.to_sym, agent_definition, chat, is_delegation: true)
324
- end
325
- end
326
-
327
- # Setup context for an agent (primary or delegation instance)
328
- def setup_agent_context(agent_name, agent_definition, chat, is_delegation: false)
329
- delegate_tool_names = agent_definition.delegates_to.map do |delegate_name|
330
- Tools::Delegate.tool_name_for(delegate_name)
331
- end
332
-
333
- context = Agent::Context.new(
334
- name: agent_name,
335
- swarm_id: @swarm.swarm_id,
336
- parent_swarm_id: @swarm.parent_swarm_id,
337
- delegation_tools: delegate_tool_names,
338
- metadata: { is_delegation_instance: is_delegation },
339
- )
340
-
341
- # Store context (only for primaries)
342
- @agent_contexts[agent_name] = context unless is_delegation
343
-
344
- # Always set agent context on chat
345
- chat.setup_context(context) if chat.respond_to?(:setup_context)
346
-
347
- # Configure logging if enabled
348
- return unless LogStream.emitter
349
-
350
- chat.setup_logging if chat.respond_to?(:setup_logging)
351
-
352
- # Emit validation warnings (only for primaries, not each delegation instance)
353
- emit_validation_warnings(agent_name, agent_definition) unless is_delegation
354
- end
355
-
356
- # Emit validation warnings as log events
357
- #
358
- # This validates the agent definition and emits any warnings as log events
359
- # through LogStream (so formatters can handle them).
360
- #
361
- # @param agent_name [Symbol] Agent name
362
- # @param agent_definition [Agent::Definition] Agent definition to validate
363
- # @return [void]
364
- def emit_validation_warnings(agent_name, agent_definition)
365
- warnings = agent_definition.validate
366
-
367
- warnings.each do |warning|
368
- case warning[:type]
369
- when :model_not_found
370
- LogStream.emit(
371
- type: "model_lookup_warning",
372
- agent: agent_name,
373
- model: warning[:model],
374
- error_message: warning[:error_message],
375
- suggestions: warning[:suggestions],
376
- timestamp: Time.now.utc.iso8601,
377
- )
378
- end
379
- end
380
- end
381
-
382
- # Pass 4: Configure hook system
383
- #
384
- # Setup the callback system for each agent, integrating with RubyLLM callbacks.
385
- def pass_4_configure_hooks
386
- # Configure hooks for PRIMARY agents
387
- @agents.each do |agent_name, chat|
388
- configure_hooks_for_agent(agent_name, chat)
389
- end
390
-
391
- # Configure hooks for DELEGATION instances
392
- @swarm.delegation_instances.each do |instance_name, chat|
393
- configure_hooks_for_agent(instance_name.to_sym, chat)
394
- end
395
- end
396
-
397
- # Configure hooks for an agent (primary or delegation instance)
398
- def configure_hooks_for_agent(agent_name, chat)
399
- base_name = extract_base_name(agent_name)
400
- agent_definition = @swarm.agent_definitions[base_name]
401
-
402
- chat.setup_hooks(
403
- registry: @swarm.hook_registry,
404
- agent_definition: agent_definition,
405
- swarm: @swarm,
406
- ) if chat.respond_to?(:setup_hooks)
407
- end
408
-
409
- # Pass 5: Apply YAML hooks
410
- #
411
- # If the swarm was loaded from YAML with agent-specific hooks,
412
- # apply them now via HooksAdapter.
413
- def pass_5_apply_yaml_hooks
414
- return unless @swarm.config_for_hooks
415
-
416
- # Apply YAML hooks to PRIMARY agents
417
- @agents.each do |agent_name, chat|
418
- apply_yaml_hooks_for_agent(agent_name, chat)
419
- end
420
-
421
- # Apply YAML hooks to DELEGATION instances
422
- @swarm.delegation_instances.each do |instance_name, chat|
423
- apply_yaml_hooks_for_agent(instance_name.to_sym, chat)
424
- end
425
- end
426
-
427
- # Apply YAML hooks for an agent (primary or delegation instance)
428
- def apply_yaml_hooks_for_agent(agent_name, chat)
429
- base_name = extract_base_name(agent_name)
430
- agent_config = @swarm.config_for_hooks.agents[base_name]
431
- return unless agent_config
432
-
433
- # Configuration.agents now returns hashes, not Definitions
434
- hooks = agent_config.is_a?(Hash) ? agent_config[:hooks] : agent_config.hooks
435
- return unless hooks&.any?
436
-
437
- Hooks::Adapter.apply_agent_hooks(chat, agent_name, hooks, @swarm.name)
438
- end
439
-
440
- # Create Agent::Chat instance with rate limiting
441
- #
442
- # @param agent_name [Symbol] Agent name
443
- # @param agent_definition [Agent::Definition] Agent definition object
444
- # @param tool_configurator [ToolConfigurator] Tool configuration helper
445
- # @return [Agent::Chat] Configured agent chat instance
446
- def create_agent_chat(agent_name, agent_definition, tool_configurator)
447
- chat = Agent::Chat.new(
448
- definition: agent_definition.to_h,
449
- agent_name: agent_name,
450
- global_semaphore: @swarm.global_semaphore,
451
- )
452
-
453
- # Set agent name on provider for logging (if provider supports it)
454
- chat.provider.agent_name = agent_name if chat.provider.respond_to?(:agent_name=)
455
-
456
- # Register tools using ToolConfigurator
457
- tool_configurator.register_all_tools(
458
- chat: chat,
459
- agent_name: agent_name,
460
- agent_definition: agent_definition,
461
- )
462
-
463
- # Register MCP servers using McpConfigurator
464
- if agent_definition.mcp_servers.any?
465
- mcp_configurator = McpConfigurator.new(@swarm)
466
- mcp_configurator.register_mcp_servers(chat, agent_definition.mcp_servers, agent_name: agent_name)
467
- end
468
-
469
- chat
470
- end
471
-
472
- # Create a delegation-specific instance of an agent
473
- #
474
- # V7.0: Simplified - just calls register_all_tools with instance_name
475
- #
476
- # @param instance_name [String] Unique instance name ("base@delegator")
477
- # @param base_name [Symbol] Base agent name (for definition lookup)
478
- # @param agent_definition [Agent::Definition] Base agent definition
479
- # @param tool_configurator [ToolConfigurator] Shared tool configurator
480
- # @return [Agent::Chat] Delegation-specific chat instance
481
- def create_agent_chat_for_delegation(instance_name:, base_name:, agent_definition:, tool_configurator:)
482
- # Create chat with instance_name for isolated conversation + tool state
483
- chat = Agent::Chat.new(
484
- definition: agent_definition.to_h,
485
- agent_name: instance_name.to_sym, # Full instance name for isolation
486
- global_semaphore: @swarm.global_semaphore,
487
- )
488
-
489
- # Set provider agent name for logging
490
- chat.provider.agent_name = instance_name if chat.provider.respond_to?(:agent_name=)
491
-
492
- # V7.0 SIMPLIFIED: Just call register_all_tools with instance_name!
493
- # Base name extraction happens automatically in create_plugin_tool
494
- tool_configurator.register_all_tools(
495
- chat: chat,
496
- agent_name: instance_name.to_sym,
497
- agent_definition: agent_definition,
498
- )
499
-
500
- # Register MCP servers (tracked by instance_name automatically)
501
- if agent_definition.mcp_servers.any?
502
- mcp_configurator = McpConfigurator.new(@swarm)
503
- mcp_configurator.register_mcp_servers(
504
- chat,
505
- agent_definition.mcp_servers,
506
- agent_name: instance_name,
507
- )
508
- end
509
-
510
- # Notify plugins (use instance_name, plugins extract base_name if needed)
511
- notify_plugins_agent_initialized(instance_name.to_sym, chat, agent_definition, tool_configurator)
512
-
513
- chat
514
- end
515
-
516
- # Register agent delegation tools
517
- #
518
- # Creates delegation tools that allow one agent to call another.
519
- #
520
- # @param chat [Agent::Chat] The chat instance
521
- # @param delegate_names [Array<Symbol>] Names of agents to delegate to
522
- # @param agent_name [Symbol] Name of the agent doing the delegating
523
- def register_delegation_tools(chat, delegate_names, agent_name:)
524
- return if delegate_names.empty?
525
-
526
- delegate_names.each do |delegate_name|
527
- delegate_name_sym = delegate_name.to_sym
528
- delegate_name_str = delegate_name.to_s
529
-
530
- # Check if target is a local agent
531
- if @agents.key?(delegate_name_sym)
532
- # Delegate to local agent
533
- delegate_agent = @agents[delegate_name_sym]
534
- delegate_definition = @swarm.agent_definitions[delegate_name_sym]
535
-
536
- tool = create_delegation_tool(
537
- name: delegate_name_str,
538
- description: delegate_definition.description,
539
- delegate_chat: delegate_agent,
540
- agent_name: agent_name,
541
- delegating_chat: chat,
542
- )
543
-
544
- chat.add_tool(tool)
545
- elsif @swarm.swarm_registry&.registered?(delegate_name_str)
546
- # Delegate to registered swarm
547
- tool = create_delegation_tool(
548
- name: delegate_name_str,
549
- description: "External swarm: #{delegate_name_str}",
550
- delegate_chat: nil, # Swarm delegation - no direct chat
551
- agent_name: agent_name,
552
- delegating_chat: chat,
553
- )
554
-
555
- chat.add_tool(tool)
556
- else
557
- raise ConfigurationError, "Agent '#{agent_name}' delegates to unknown target '#{delegate_name_str}' (not a local agent or registered swarm)"
558
- end
559
- end
560
- end
561
-
562
- # Create plugin storages for all agents
563
- #
564
- # Iterates through all registered plugins and asks each to create
565
- # storage for agents that need it.
566
- #
567
- # @return [void]
568
- def create_plugin_storages
569
- PluginRegistry.all.each do |plugin|
570
- @swarm.agent_definitions.each do |agent_name, agent_definition|
571
- # Check if this plugin needs storage for this agent
572
- next unless plugin.storage_enabled?(agent_definition)
573
-
574
- # Get plugin config for this agent
575
- config = get_plugin_config(agent_definition, plugin.name)
576
- next unless config
577
-
578
- # Parse config through plugin
579
- parsed_config = plugin.parse_config(config)
580
-
581
- # Create plugin storage
582
- storage = plugin.create_storage(agent_name: agent_name, config: parsed_config)
583
-
584
- # Store in plugin_storages: { plugin_name => { agent_name => storage } }
585
- @swarm.plugin_storages[plugin.name] ||= {}
586
- @swarm.plugin_storages[plugin.name][agent_name] = storage
587
- end
588
- end
589
- end
590
-
591
- # Get plugin-specific config from agent definition
592
- #
593
- # Uses the generic plugin_configs accessor to retrieve plugin-specific config.
594
- # E.g., memory plugin config is accessed via `agent_definition.plugin_config(:memory)`
595
- #
596
- # @param agent_definition [Agent::Definition] Agent definition
597
- # @param plugin_name [Symbol] Plugin name
598
- # @return [Object, nil] Plugin config or nil
599
- def get_plugin_config(agent_definition, plugin_name)
600
- # Use generic plugin config accessor
601
- agent_definition.plugin_config(plugin_name)
602
- end
603
-
604
- # Notify all plugins that an agent was initialized
605
- #
606
- # Plugins can register additional tools, mark tools immutable, etc.
607
- #
608
- # @param agent_name [Symbol] Agent name
609
- # @param chat [Agent::Chat] Chat instance
610
- # @param agent_definition [Agent::Definition] Agent definition
611
- # @param tool_configurator [ToolConfigurator] Tool configurator
612
- # @return [void]
613
- def notify_plugins_agent_initialized(agent_name, chat, agent_definition, tool_configurator)
614
- PluginRegistry.all.each do |plugin|
615
- # Get plugin storage for this agent (if any)
616
- plugin_storages = @swarm.plugin_storages[plugin.name] || {}
617
- storage = plugin_storages[agent_name]
618
-
619
- # Build context for plugin
620
- context = {
621
- storage: storage,
622
- agent_definition: agent_definition,
623
- tool_configurator: tool_configurator,
624
- }
625
-
626
- # Notify plugin
627
- plugin.on_agent_initialized(agent_name: agent_name, agent: chat, context: context)
628
- end
629
- end
630
-
631
- # Determine if we should skip creating a primary agent
632
- #
633
- # Skip if:
634
- # - NOT the lead agent, AND
635
- # - Has shared_across_delegations: false (isolated mode), AND
636
- # - Is only referenced as a delegate (not used standalone)
637
- #
638
- # @param name [Symbol] Agent name
639
- # @param agent_definition [Agent::Definition] Agent definition
640
- # @return [Boolean] True if should skip primary creation
641
- def should_skip_primary_creation?(name, agent_definition)
642
- # Always create lead agent
643
- return false if name == @swarm.lead_agent
644
-
645
- # If shared mode, create primary (delegates will use it)
646
- return false if agent_definition.shared_across_delegations
647
-
648
- # Skip if only used as a delegate
649
- only_referenced_as_delegate?(name)
650
- end
651
-
652
- # Check if an agent is only referenced as a delegate
653
- #
654
- # @param name [Symbol] Agent name
655
- # @return [Boolean] True if only referenced as delegate
656
- def only_referenced_as_delegate?(name)
657
- # Check if any agent delegates to this one
658
- referenced_as_delegate = @swarm.agent_definitions.any? do |_agent_name, definition|
659
- definition.delegates_to.include?(name)
660
- end
661
-
662
- # Skip if referenced as delegate (and not lead, already checked above)
663
- referenced_as_delegate
664
- end
665
-
666
- # Extract base agent name from instance name
667
- #
668
- # @param instance_name [Symbol, String] Instance name (may be delegation instance)
669
- # @return [Symbol] Base agent name
670
- def extract_base_name(instance_name)
671
- instance_name.to_s.split("@").first.to_sym
672
- end
673
-
674
- # Check if instance name is a delegation instance
675
- #
676
- # @param instance_name [Symbol, String] Instance name
677
- # @return [Boolean] True if delegation instance (contains '@')
678
- def delegation_instance?(instance_name)
679
- instance_name.to_s.include?("@")
680
- end
681
- end
682
- end
683
- end