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,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