swarm_memory 2.1.4 → 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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. data/lib/swarm_memory.rb +7 -2
  4. metadata +6 -185
  5. data/lib/claude_swarm/base_executor.rb +0 -133
  6. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  7. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  8. data/lib/claude_swarm/cli.rb +0 -697
  9. data/lib/claude_swarm/commands/ps.rb +0 -215
  10. data/lib/claude_swarm/commands/show.rb +0 -139
  11. data/lib/claude_swarm/configuration.rb +0 -373
  12. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  13. data/lib/claude_swarm/json_handler.rb +0 -91
  14. data/lib/claude_swarm/mcp_generator.rb +0 -243
  15. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  16. data/lib/claude_swarm/openai/executor.rb +0 -256
  17. data/lib/claude_swarm/openai/responses.rb +0 -319
  18. data/lib/claude_swarm/orchestrator.rb +0 -878
  19. data/lib/claude_swarm/process_tracker.rb +0 -78
  20. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  21. data/lib/claude_swarm/session_path.rb +0 -42
  22. data/lib/claude_swarm/settings_generator.rb +0 -77
  23. data/lib/claude_swarm/system_utils.rb +0 -46
  24. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  25. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  27. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  28. data/lib/claude_swarm/version.rb +0 -5
  29. data/lib/claude_swarm/worktree_manager.rb +0 -475
  30. data/lib/claude_swarm/yaml_loader.rb +0 -22
  31. data/lib/claude_swarm.rb +0 -67
  32. data/lib/swarm_cli/cli.rb +0 -201
  33. data/lib/swarm_cli/command_registry.rb +0 -61
  34. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  35. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  36. data/lib/swarm_cli/commands/migrate.rb +0 -55
  37. data/lib/swarm_cli/commands/run.rb +0 -173
  38. data/lib/swarm_cli/config_loader.rb +0 -98
  39. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  40. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  41. data/lib/swarm_cli/interactive_repl.rb +0 -924
  42. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  43. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  44. data/lib/swarm_cli/migrate_options.rb +0 -54
  45. data/lib/swarm_cli/migrator.rb +0 -132
  46. data/lib/swarm_cli/options.rb +0 -151
  47. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  48. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  49. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  50. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  51. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  52. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  53. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  54. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  55. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  56. data/lib/swarm_cli/ui/icons.rb +0 -36
  57. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  58. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  59. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  60. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  61. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  62. data/lib/swarm_cli/version.rb +0 -5
  63. data/lib/swarm_cli.rb +0 -46
  64. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  65. data/lib/swarm_sdk/agent/builder.rb +0 -552
  66. data/lib/swarm_sdk/agent/chat.rb +0 -774
  67. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  68. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  69. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  70. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  71. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  72. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  73. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  75. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  76. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  77. data/lib/swarm_sdk/agent/context.rb +0 -116
  78. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  79. data/lib/swarm_sdk/agent/definition.rb +0 -477
  80. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  81. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  82. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  83. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  84. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  85. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  86. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  87. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  88. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  89. data/lib/swarm_sdk/configuration.rb +0 -135
  90. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  91. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  92. data/lib/swarm_sdk/context_compactor.rb +0 -335
  93. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  94. data/lib/swarm_sdk/context_management/context.rb +0 -328
  95. data/lib/swarm_sdk/defaults.rb +0 -196
  96. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  97. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  98. data/lib/swarm_sdk/hooks/context.rb +0 -197
  99. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  100. data/lib/swarm_sdk/hooks/error.rb +0 -29
  101. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  102. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  103. data/lib/swarm_sdk/hooks/result.rb +0 -150
  104. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  105. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  106. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  107. data/lib/swarm_sdk/log_collector.rb +0 -227
  108. data/lib/swarm_sdk/log_stream.rb +0 -127
  109. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  110. data/lib/swarm_sdk/model_aliases.json +0 -8
  111. data/lib/swarm_sdk/models.json +0 -1
  112. data/lib/swarm_sdk/models.rb +0 -120
  113. data/lib/swarm_sdk/node_context.rb +0 -245
  114. data/lib/swarm_sdk/observer/builder.rb +0 -81
  115. data/lib/swarm_sdk/observer/config.rb +0 -45
  116. data/lib/swarm_sdk/observer/manager.rb +0 -236
  117. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  118. data/lib/swarm_sdk/permissions/config.rb +0 -239
  119. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  120. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  121. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  122. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  123. data/lib/swarm_sdk/plugin.rb +0 -309
  124. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  125. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  126. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  127. data/lib/swarm_sdk/restore_result.rb +0 -65
  128. data/lib/swarm_sdk/result.rb +0 -123
  129. data/lib/swarm_sdk/snapshot.rb +0 -156
  130. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  131. data/lib/swarm_sdk/state_restorer.rb +0 -476
  132. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  133. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  134. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  135. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  136. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  137. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  138. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  139. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  140. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  141. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  142. data/lib/swarm_sdk/swarm.rb +0 -717
  143. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  144. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  145. data/lib/swarm_sdk/tools/bash.rb +0 -282
  146. data/lib/swarm_sdk/tools/clock.rb +0 -44
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  160. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  161. data/lib/swarm_sdk/tools/read.rb +0 -261
  162. data/lib/swarm_sdk/tools/registry.rb +0 -205
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  166. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  167. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  168. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  169. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  170. data/lib/swarm_sdk/tools/think.rb +0 -98
  171. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  172. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  173. data/lib/swarm_sdk/tools/write.rb +0 -112
  174. data/lib/swarm_sdk/utils.rb +0 -68
  175. data/lib/swarm_sdk/validation_result.rb +0 -33
  176. data/lib/swarm_sdk/version.rb +0 -5
  177. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  178. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  179. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  180. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  181. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  182. data/lib/swarm_sdk/workflow.rb +0 -554
  183. data/lib/swarm_sdk.rb +0 -524
  184. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -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