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,150 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Hook triggering methods for swarm lifecycle events
6
- #
7
- # Extracted from Swarm to reduce class size and centralize hook execution logic.
8
- # These methods build contexts and execute hooks via the hook registry.
9
- module HookTriggers
10
- # Add a default callback for an event
11
- #
12
- # @param event [Symbol] Event type (:pre_tool_use, :post_tool_use, etc.)
13
- # @param matcher [Hash, nil] Optional matcher to filter events
14
- # @param priority [Integer] Callback priority (higher = later)
15
- # @param block [Proc] Hook implementation
16
- # @return [self]
17
- def add_default_callback(event, matcher: nil, priority: 0, &block)
18
- @hook_registry.add_default(event, matcher: matcher, priority: priority, &block)
19
- self
20
- end
21
-
22
- # Trigger swarm_stop hooks and check for reprompt
23
- #
24
- # @param result [Result] The execution result
25
- # @return [Hooks::Result, nil] Hook result (reprompt action if applicable)
26
- def trigger_swarm_stop(result)
27
- context = build_swarm_stop_context(result)
28
- executor = Hooks::Executor.new(@hook_registry, logger: RubyLLM.logger)
29
- executor.execute_safe(event: :swarm_stop, context: context, callbacks: [])
30
- rescue StandardError => e
31
- LogStream.emit_error(e, source: "hook_triggers", context: "swarm_stop", agent: @lead_agent)
32
- RubyLLM.logger.debug("SwarmSDK: Error in swarm_stop hook: #{e.message}")
33
- nil
34
- end
35
-
36
- # Trigger swarm_stop for final event emission (called in ensure block)
37
- #
38
- # @param result [Result, nil] Execution result
39
- # @param start_time [Time] Execution start time
40
- # @param logs [Array] Collected logs
41
- # @return [void]
42
- def trigger_swarm_stop_final(result, start_time, logs)
43
- result ||= Result.new(
44
- content: nil,
45
- agent: @lead_agent&.to_s || "unknown",
46
- logs: logs,
47
- duration: Time.now - start_time,
48
- error: StandardError.new("Unknown error"),
49
- )
50
-
51
- context = build_swarm_stop_context(result)
52
- executor = Hooks::Executor.new(@hook_registry, logger: RubyLLM.logger)
53
- executor.execute_safe(event: :swarm_stop, context: context, callbacks: [])
54
- rescue StandardError => e
55
- LogStream.emit_error(e, source: "hook_triggers", context: "swarm_stop_final", agent: @lead_agent)
56
- RubyLLM.logger.debug("SwarmSDK: Error in swarm_stop final emission: #{e.message}")
57
- end
58
-
59
- private
60
-
61
- # Build swarm_stop context (DRY - used by both trigger methods)
62
- #
63
- # @param result [Result] Execution result
64
- # @return [Hooks::Context] Hook context for swarm_stop event
65
- def build_swarm_stop_context(result)
66
- Hooks::Context.new(
67
- event: :swarm_stop,
68
- agent_name: @lead_agent.to_s,
69
- swarm: self,
70
- metadata: {
71
- swarm_name: @name,
72
- lead_agent: @lead_agent,
73
- last_agent: result.agent,
74
- content: result.content,
75
- success: result.success?,
76
- duration: result.duration,
77
- total_cost: result.total_cost,
78
- total_tokens: result.total_tokens,
79
- agents_involved: result.agents_involved,
80
- result: result,
81
- timestamp: Time.now.utc.iso8601,
82
- },
83
- )
84
- end
85
-
86
- # Trigger swarm_start hooks when swarm execution begins
87
- #
88
- # @param prompt [String] The user's task prompt
89
- # @return [Hooks::Result, nil] Result with stdout to append (if exit 0) or nil
90
- # @raise [Hooks::Error] If hook halts execution
91
- def trigger_swarm_start(prompt)
92
- context = Hooks::Context.new(
93
- event: :swarm_start,
94
- agent_name: @lead_agent.to_s,
95
- swarm: self,
96
- metadata: {
97
- swarm_name: @name,
98
- lead_agent: @lead_agent,
99
- prompt: prompt,
100
- timestamp: Time.now.utc.iso8601,
101
- },
102
- )
103
-
104
- executor = Hooks::Executor.new(@hook_registry, logger: RubyLLM.logger)
105
- result = executor.execute_safe(event: :swarm_start, context: context, callbacks: [])
106
-
107
- # Halt execution if hook requests it
108
- raise Hooks::Error, "Swarm start halted by hook: #{result.value}" if result.halt?
109
-
110
- # Return result so caller can check for replace (stdout injection)
111
- result
112
- rescue StandardError => e
113
- LogStream.emit_error(e, source: "hook_triggers", context: "swarm_start", agent: @lead_agent)
114
- RubyLLM.logger.debug("SwarmSDK: Error in swarm_start hook: #{e.message}")
115
- raise
116
- end
117
-
118
- # Trigger first_message hooks when first user message is sent
119
- #
120
- # @param prompt [String] The first user message
121
- # @return [void]
122
- # @raise [Hooks::Error] If hook halts execution
123
- def trigger_first_message(prompt)
124
- return if @hook_registry.get_defaults(:first_message).empty?
125
-
126
- context = Hooks::Context.new(
127
- event: :first_message,
128
- agent_name: @lead_agent.to_s,
129
- swarm: self,
130
- metadata: {
131
- swarm_name: @name,
132
- lead_agent: @lead_agent,
133
- prompt: prompt,
134
- timestamp: Time.now.utc.iso8601,
135
- },
136
- )
137
-
138
- executor = Hooks::Executor.new(@hook_registry, logger: RubyLLM.logger)
139
- result = executor.execute_safe(event: :first_message, context: context, callbacks: [])
140
-
141
- # Halt execution if hook requests it
142
- raise Hooks::Error, "First message halted by hook: #{result.value}" if result.halt?
143
- rescue StandardError => e
144
- LogStream.emit_error(e, source: "hook_triggers", context: "first_message", agent: @lead_agent)
145
- RubyLLM.logger.debug("SwarmSDK: Error in first_message hook: #{e.message}")
146
- raise
147
- end
148
- end
149
- end
150
- end
@@ -1,340 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Logging callbacks for swarm events
6
- #
7
- # Extracted from Swarm to reduce class size and eliminate repetitive callback patterns.
8
- # These callbacks emit structured log events to LogStream for monitoring and debugging.
9
- module LoggingCallbacks
10
- # Register default logging callbacks for all swarm events
11
- #
12
- # Sets up low-priority callbacks that emit structured events to LogStream.
13
- # These callbacks only fire when LogStream.emitter is set (logging enabled).
14
- def register_default_logging_callbacks
15
- register_swarm_lifecycle_callbacks
16
- register_agent_lifecycle_callbacks
17
- register_tool_execution_callbacks
18
- register_context_warning_callback
19
- end
20
-
21
- # Setup logging infrastructure for an execution
22
- #
23
- # @param logs [Array] Log collection array
24
- # @yield [entry] Block called for each log entry
25
- def setup_logging(logs)
26
- # Force fresh subscription array for this execution
27
- Fiber[:log_subscriptions] = []
28
-
29
- # Subscribe to collect logs and forward to user's block
30
- LogCollector.subscribe do |entry|
31
- logs << entry
32
- yield(entry) if block_given?
33
- end
34
-
35
- # Set LogStream to use LogCollector as emitter
36
- LogStream.emitter = LogCollector
37
- end
38
-
39
- # Emit agent_start events if agents were initialized before logging was set up
40
- #
41
- # When agents are initialized BEFORE logging (e.g., via restore()),
42
- # we need to retroactively set up logging callbacks and emit agent_start events.
43
- def emit_retroactive_agent_start_events
44
- return if !@agents_initialized || @agent_start_events_emitted
45
-
46
- # Setup logging callbacks for all agents (they were skipped during initialization)
47
- setup_logging_for_all_agents
48
-
49
- # Emit agent_start events now that logging is ready
50
- emit_agent_start_events
51
- @agent_start_events_emitted = true
52
- end
53
-
54
- # Setup logging callbacks for all initialized agents
55
- #
56
- # Called after restore() when logging is enabled. Sets up logging callbacks
57
- # for each agent so that subsequent events are captured.
58
- def setup_logging_for_all_agents
59
- # Setup for PRIMARY agents
60
- @agents.each_value do |chat|
61
- chat.setup_logging if chat.respond_to?(:setup_logging)
62
- end
63
-
64
- # Setup for DELEGATION instances
65
- @delegation_instances.each_value do |chat|
66
- chat.setup_logging if chat.respond_to?(:setup_logging)
67
- end
68
- end
69
-
70
- # Emit agent_start events for all initialized agents
71
- #
72
- # Called retroactively when agents were initialized before logging was enabled.
73
- # Emits agent_start events so log stream captures complete agent lifecycle.
74
- def emit_agent_start_events
75
- return unless LogStream.emitter
76
-
77
- # Emit for PRIMARY agents
78
- @agents.each do |agent_name, chat|
79
- emit_agent_start_for(agent_name, chat, is_delegation: false)
80
- end
81
-
82
- # Emit for DELEGATION instances
83
- @delegation_instances.each do |instance_name, chat|
84
- base_name = extract_base_name(instance_name)
85
- emit_agent_start_for(instance_name.to_sym, chat, is_delegation: true, base_name: base_name)
86
- end
87
-
88
- # Mark as emitted to prevent duplicate emissions
89
- @agent_start_events_emitted = true
90
- end
91
-
92
- # Emit a single agent_start event
93
- #
94
- # @param agent_name [Symbol] Agent name (or instance name for delegations)
95
- # @param chat [Agent::Chat] Agent chat instance
96
- # @param is_delegation [Boolean] Whether this is a delegation instance
97
- # @param base_name [String, nil] Base agent name for delegations
98
- def emit_agent_start_for(agent_name, chat, is_delegation:, base_name: nil)
99
- base_name ||= agent_name
100
- agent_def = @agent_definitions[base_name]
101
-
102
- # Build plugin storage info using base name
103
- plugin_storage_info = {}
104
- @plugin_storages.each do |plugin_name, agent_storages|
105
- next unless agent_storages.key?(base_name)
106
-
107
- plugin_storage_info[plugin_name] = {
108
- enabled: true,
109
- config: agent_def.respond_to?(plugin_name) ? extract_plugin_config_info(agent_def.public_send(plugin_name)) : nil,
110
- }
111
- end
112
-
113
- LogStream.emit(
114
- type: "agent_start",
115
- agent: agent_name,
116
- swarm_id: @swarm_id,
117
- parent_swarm_id: @parent_swarm_id,
118
- swarm_name: @name,
119
- model: agent_def.model,
120
- provider: agent_def.provider || "openai",
121
- directory: agent_def.directory,
122
- system_prompt: agent_def.system_prompt,
123
- tools: chat.tool_names,
124
- delegates_to: agent_def.delegates_to,
125
- plugin_storages: plugin_storage_info,
126
- is_delegation_instance: is_delegation,
127
- base_agent: (base_name if is_delegation),
128
- timestamp: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
129
- )
130
- end
131
-
132
- private
133
-
134
- # Register swarm lifecycle callbacks (swarm_start, swarm_stop)
135
- def register_swarm_lifecycle_callbacks
136
- add_default_callback(:swarm_start, priority: -100) do |context|
137
- emit_swarm_start_event(context)
138
- end
139
-
140
- add_default_callback(:swarm_stop, priority: -100) do |context|
141
- emit_swarm_stop_event(context)
142
- end
143
- end
144
-
145
- # Register agent lifecycle callbacks (user_prompt, agent_step, agent_stop)
146
- def register_agent_lifecycle_callbacks
147
- add_default_callback(:user_prompt, priority: -100) do |context|
148
- emit_user_prompt_event(context)
149
- end
150
-
151
- add_default_callback(:agent_step, priority: -100) do |context|
152
- emit_agent_step_event(context)
153
- end
154
-
155
- add_default_callback(:agent_stop, priority: -100) do |context|
156
- emit_agent_stop_event(context)
157
- end
158
- end
159
-
160
- # Register tool execution callbacks (pre_tool_use, post_tool_use)
161
- def register_tool_execution_callbacks
162
- add_default_callback(:pre_tool_use, priority: -100) do |context|
163
- emit_tool_call_event(context)
164
- end
165
-
166
- add_default_callback(:post_tool_use, priority: -100) do |context|
167
- emit_tool_result_event(context)
168
- end
169
- end
170
-
171
- # Register context warning callback
172
- def register_context_warning_callback
173
- add_default_callback(:context_warning, priority: -100) do |context|
174
- emit_context_warning_event(context)
175
- end
176
- end
177
-
178
- # Emit swarm_start event
179
- def emit_swarm_start_event(context)
180
- return unless LogStream.emitter
181
-
182
- LogStream.emit(
183
- type: "swarm_start",
184
- agent: context.metadata[:lead_agent],
185
- swarm_id: @swarm_id,
186
- parent_swarm_id: @parent_swarm_id,
187
- swarm_name: context.metadata[:swarm_name],
188
- lead_agent: context.metadata[:lead_agent],
189
- prompt: context.metadata[:prompt],
190
- timestamp: context.metadata[:timestamp],
191
- )
192
- end
193
-
194
- # Emit swarm_stop event
195
- def emit_swarm_stop_event(context)
196
- return unless LogStream.emitter
197
-
198
- LogStream.emit(
199
- type: "swarm_stop",
200
- swarm_id: @swarm_id,
201
- parent_swarm_id: @parent_swarm_id,
202
- swarm_name: context.metadata[:swarm_name],
203
- lead_agent: context.metadata[:lead_agent],
204
- last_agent: context.metadata[:last_agent],
205
- content: context.metadata[:content],
206
- success: context.metadata[:success],
207
- duration: context.metadata[:duration],
208
- total_cost: context.metadata[:total_cost],
209
- total_tokens: context.metadata[:total_tokens],
210
- agents_involved: context.metadata[:agents_involved],
211
- timestamp: context.metadata[:timestamp],
212
- )
213
- end
214
-
215
- # Emit user_prompt event
216
- def emit_user_prompt_event(context)
217
- return unless LogStream.emitter
218
-
219
- LogStream.emit(
220
- type: "user_prompt",
221
- agent: context.agent_name,
222
- swarm_id: @swarm_id,
223
- parent_swarm_id: @parent_swarm_id,
224
- model: context.metadata[:model] || "unknown",
225
- provider: context.metadata[:provider] || "unknown",
226
- message_count: context.metadata[:message_count] || 0,
227
- tools: context.metadata[:tools] || [],
228
- delegates_to: context.metadata[:delegates_to] || [],
229
- source: context.metadata[:source] || "user",
230
- metadata: context.metadata,
231
- )
232
- end
233
-
234
- # Emit agent_step event (intermediate response with tool calls)
235
- def emit_agent_step_event(context)
236
- return unless LogStream.emitter
237
-
238
- metadata_without_duplicates = context.metadata.except(
239
- :model, :content, :tool_calls, :finish_reason, :usage, :tool_executions
240
- )
241
-
242
- LogStream.emit(
243
- type: "agent_step",
244
- agent: context.agent_name,
245
- swarm_id: @swarm_id,
246
- parent_swarm_id: @parent_swarm_id,
247
- model: context.metadata[:model],
248
- content: context.metadata[:content],
249
- tool_calls: context.metadata[:tool_calls],
250
- finish_reason: context.metadata[:finish_reason],
251
- usage: context.metadata[:usage],
252
- tool_executions: context.metadata[:tool_executions],
253
- metadata: metadata_without_duplicates,
254
- )
255
- end
256
-
257
- # Emit agent_stop event (final response)
258
- def emit_agent_stop_event(context)
259
- return unless LogStream.emitter
260
-
261
- metadata_without_duplicates = context.metadata.except(
262
- :model, :content, :tool_calls, :finish_reason, :usage, :tool_executions
263
- )
264
-
265
- LogStream.emit(
266
- type: "agent_stop",
267
- agent: context.agent_name,
268
- swarm_id: @swarm_id,
269
- parent_swarm_id: @parent_swarm_id,
270
- model: context.metadata[:model],
271
- content: context.metadata[:content],
272
- tool_calls: context.metadata[:tool_calls],
273
- finish_reason: context.metadata[:finish_reason],
274
- usage: context.metadata[:usage],
275
- tool_executions: context.metadata[:tool_executions],
276
- metadata: metadata_without_duplicates,
277
- )
278
- end
279
-
280
- # Emit tool_call event (pre_tool_use)
281
- def emit_tool_call_event(context)
282
- return unless LogStream.emitter
283
-
284
- LogStream.emit(
285
- type: "tool_call",
286
- agent: context.agent_name,
287
- swarm_id: @swarm_id,
288
- parent_swarm_id: @parent_swarm_id,
289
- tool_call_id: context.tool_call.id,
290
- tool: context.tool_call.name,
291
- arguments: context.tool_call.parameters,
292
- metadata: context.metadata,
293
- )
294
- end
295
-
296
- # Emit tool_result event (post_tool_use)
297
- def emit_tool_result_event(context)
298
- return unless LogStream.emitter
299
-
300
- LogStream.emit(
301
- type: "tool_result",
302
- agent: context.agent_name,
303
- swarm_id: @swarm_id,
304
- parent_swarm_id: @parent_swarm_id,
305
- tool_call_id: context.tool_result.tool_call_id,
306
- tool: context.tool_result.tool_name,
307
- result: context.tool_result.content,
308
- metadata: context.metadata,
309
- )
310
- end
311
-
312
- # Emit context_limit_warning event
313
- def emit_context_warning_event(context)
314
- return unless LogStream.emitter
315
-
316
- LogStream.emit(
317
- type: "context_limit_warning",
318
- agent: context.agent_name,
319
- swarm_id: @swarm_id,
320
- parent_swarm_id: @parent_swarm_id,
321
- model: context.metadata[:model] || "unknown",
322
- threshold: "#{context.metadata[:threshold]}%",
323
- current_usage: "#{context.metadata[:percentage]}%",
324
- tokens_used: context.metadata[:tokens_used],
325
- tokens_remaining: context.metadata[:tokens_remaining],
326
- context_limit: context.metadata[:context_limit],
327
- metadata: context.metadata,
328
- )
329
- end
330
-
331
- # Extract base name from delegation instance name
332
- #
333
- # @param instance_name [String, Symbol] Instance name (e.g., "agent@1234")
334
- # @return [Symbol] Base agent name (e.g., :agent)
335
- def extract_base_name(instance_name)
336
- instance_name.to_s.split("@").first.to_sym
337
- end
338
- end
339
- end
340
- end
@@ -1,154 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Handles MCP (Model Context Protocol) server configuration and client management
6
- #
7
- # Responsibilities:
8
- # - Register MCP servers for agents
9
- # - Initialize MCP clients (stdio, SSE, streamable transports)
10
- # - Build transport-specific configurations
11
- # - Track clients for cleanup
12
- #
13
- # This encapsulates all MCP-related logic that was previously in Swarm.
14
- class McpConfigurator
15
- def initialize(swarm)
16
- @swarm = swarm
17
- @mcp_clients = swarm.mcp_clients
18
- end
19
-
20
- # Register MCP servers for an agent
21
- #
22
- # Connects to MCP servers and registers their tools with the agent's chat instance.
23
- # Supports stdio, SSE, and HTTP (streamable) transports.
24
- #
25
- # @param chat [AgentChat] The agent's chat instance
26
- # @param mcp_server_configs [Array<Hash>] MCP server configurations
27
- # @param agent_name [Symbol] Agent name for tracking clients
28
- def register_mcp_servers(chat, mcp_server_configs, agent_name:)
29
- return if mcp_server_configs.nil? || mcp_server_configs.empty?
30
-
31
- # Ensure MCP logging is configured before creating clients
32
- Swarm.apply_mcp_logging_configuration
33
-
34
- mcp_server_configs.each do |server_config|
35
- client = initialize_mcp_client(server_config)
36
-
37
- # Store client for cleanup
38
- @mcp_clients[agent_name] << client
39
-
40
- # Fetch tools from MCP server and register with chat
41
- # Tools are already in RubyLLM::Tool format
42
- tools = client.tools
43
- tools.each { |tool| chat.add_tool(tool) }
44
-
45
- RubyLLM.logger.debug("SwarmSDK: Registered #{tools.size} tools from MCP server '#{server_config[:name]}' for agent #{agent_name}")
46
- rescue StandardError => e
47
- RubyLLM.logger.error("SwarmSDK: Failed to initialize MCP server '#{server_config[:name]}' for agent #{agent_name}: #{e.message}")
48
- raise ConfigurationError, "Failed to initialize MCP server '#{server_config[:name]}': #{e.message}"
49
- end
50
- end
51
-
52
- # Build transport-specific configuration for MCP client
53
- #
54
- # This method is public for testing delegation from Swarm.
55
- #
56
- # @param transport_type [Symbol] Transport type (:stdio, :sse, :streamable)
57
- # @param config [Hash] MCP server configuration
58
- # @return [Hash] Transport-specific configuration
59
- def build_transport_config(transport_type, config)
60
- case transport_type
61
- when :stdio
62
- build_stdio_config(config)
63
- when :sse
64
- build_sse_config(config)
65
- when :streamable
66
- build_streamable_config(config)
67
- else
68
- raise ArgumentError, "Unsupported transport type: #{transport_type}"
69
- end
70
- end
71
-
72
- private
73
-
74
- # Initialize an MCP client from configuration
75
- #
76
- # @param config [Hash] MCP server configuration
77
- # @return [RubyLLM::MCP::Client] Initialized MCP client
78
- def initialize_mcp_client(config)
79
- # Convert timeout from seconds to milliseconds
80
- timeout_seconds = config[:timeout] || 30
81
- timeout_ms = timeout_seconds * 1000
82
-
83
- # Determine transport type
84
- transport_type = determine_transport_type(config[:type])
85
-
86
- # Build transport-specific configuration
87
- client_config = build_transport_config(transport_type, config)
88
-
89
- # Create and start MCP client
90
- RubyLLM::MCP.client(
91
- name: config[:name],
92
- transport_type: transport_type,
93
- request_timeout: timeout_ms,
94
- config: client_config,
95
- )
96
- end
97
-
98
- # Determine transport type from configuration
99
- #
100
- # @param type [Symbol, String, nil] Transport type from config
101
- # @return [Symbol] Normalized transport type
102
- def determine_transport_type(type)
103
- case type&.to_sym
104
- when :stdio then :stdio
105
- when :sse then :sse
106
- when :http, :streamable then :streamable
107
- else
108
- raise ArgumentError, "Unknown MCP transport type: #{type}"
109
- end
110
- end
111
-
112
- # Build stdio transport configuration
113
- #
114
- # @param config [Hash] MCP server configuration
115
- # @return [Hash] Stdio configuration
116
- def build_stdio_config(config)
117
- {
118
- command: config[:command],
119
- args: config[:args] || [],
120
- env: Utils.stringify_keys(config[:env] || {}),
121
- }
122
- end
123
-
124
- # Build SSE transport configuration
125
- #
126
- # @param config [Hash] MCP server configuration
127
- # @return [Hash] SSE configuration
128
- def build_sse_config(config)
129
- {
130
- url: config[:url],
131
- headers: config[:headers] || {},
132
- version: config[:version]&.to_sym || :http2,
133
- }
134
- end
135
-
136
- # Build streamable (HTTP) transport configuration
137
- #
138
- # @param config [Hash] MCP server configuration
139
- # @return [Hash] Streamable configuration
140
- def build_streamable_config(config)
141
- streamable_config = {
142
- url: config[:url],
143
- headers: config[:headers] || {},
144
- version: config[:version]&.to_sym || :http2,
145
- }
146
-
147
- # Only include rate_limit if present
148
- streamable_config[:rate_limit] = config[:rate_limit] if config[:rate_limit]
149
-
150
- streamable_config
151
- end
152
- end
153
- end
154
- end