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.
- checksums.yaml +4 -4
- data/lib/swarm_memory/version.rb +1 -1
- metadata +5 -184
- data/lib/claude_swarm/base_executor.rb +0 -133
- data/lib/claude_swarm/claude_code_executor.rb +0 -349
- data/lib/claude_swarm/claude_mcp_server.rb +0 -78
- data/lib/claude_swarm/cli.rb +0 -697
- data/lib/claude_swarm/commands/ps.rb +0 -215
- data/lib/claude_swarm/commands/show.rb +0 -139
- data/lib/claude_swarm/configuration.rb +0 -373
- data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
- data/lib/claude_swarm/json_handler.rb +0 -91
- data/lib/claude_swarm/mcp_generator.rb +0 -230
- data/lib/claude_swarm/openai/chat_completion.rb +0 -256
- data/lib/claude_swarm/openai/executor.rb +0 -256
- data/lib/claude_swarm/openai/responses.rb +0 -319
- data/lib/claude_swarm/orchestrator.rb +0 -878
- data/lib/claude_swarm/process_tracker.rb +0 -78
- data/lib/claude_swarm/session_cost_calculator.rb +0 -209
- data/lib/claude_swarm/session_path.rb +0 -42
- data/lib/claude_swarm/settings_generator.rb +0 -77
- data/lib/claude_swarm/system_utils.rb +0 -46
- data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
- data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
- data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
- data/lib/claude_swarm/tools/task_tool.rb +0 -63
- data/lib/claude_swarm/version.rb +0 -5
- data/lib/claude_swarm/worktree_manager.rb +0 -475
- data/lib/claude_swarm/yaml_loader.rb +0 -22
- data/lib/claude_swarm.rb +0 -67
- data/lib/swarm_cli/cli.rb +0 -201
- data/lib/swarm_cli/command_registry.rb +0 -61
- data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
- data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
- data/lib/swarm_cli/commands/migrate.rb +0 -55
- data/lib/swarm_cli/commands/run.rb +0 -173
- data/lib/swarm_cli/config_loader.rb +0 -98
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
- data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
- data/lib/swarm_cli/interactive_repl.rb +0 -924
- data/lib/swarm_cli/mcp_serve_options.rb +0 -44
- data/lib/swarm_cli/mcp_tools_options.rb +0 -59
- data/lib/swarm_cli/migrate_options.rb +0 -54
- data/lib/swarm_cli/migrator.rb +0 -132
- data/lib/swarm_cli/options.rb +0 -151
- data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
- data/lib/swarm_cli/ui/components/content_block.rb +0 -120
- data/lib/swarm_cli/ui/components/divider.rb +0 -57
- data/lib/swarm_cli/ui/components/panel.rb +0 -62
- data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
- data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
- data/lib/swarm_cli/ui/formatters/number.rb +0 -58
- data/lib/swarm_cli/ui/formatters/text.rb +0 -77
- data/lib/swarm_cli/ui/formatters/time.rb +0 -73
- data/lib/swarm_cli/ui/icons.rb +0 -36
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
- data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
- data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
- data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
- data/lib/swarm_cli/version.rb +0 -5
- data/lib/swarm_cli.rb +0 -46
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
- data/lib/swarm_sdk/agent/builder.rb +0 -552
- data/lib/swarm_sdk/agent/chat.rb +0 -774
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
- data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
- data/lib/swarm_sdk/agent/context.rb +0 -116
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -477
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/builders/base_builder.rb +0 -409
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
- data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
- data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
- data/lib/swarm_sdk/concerns/validatable.rb +0 -55
- data/lib/swarm_sdk/configuration/parser.rb +0 -353
- data/lib/swarm_sdk/configuration/translator.rb +0 -255
- data/lib/swarm_sdk/configuration.rb +0 -135
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
- data/lib/swarm_sdk/context_compactor.rb +0 -335
- data/lib/swarm_sdk/context_management/builder.rb +0 -128
- data/lib/swarm_sdk/context_management/context.rb +0 -328
- data/lib/swarm_sdk/defaults.rb +0 -196
- data/lib/swarm_sdk/events_to_messages.rb +0 -199
- data/lib/swarm_sdk/hooks/adapter.rb +0 -359
- data/lib/swarm_sdk/hooks/context.rb +0 -197
- data/lib/swarm_sdk/hooks/definition.rb +0 -80
- data/lib/swarm_sdk/hooks/error.rb +0 -29
- data/lib/swarm_sdk/hooks/executor.rb +0 -146
- data/lib/swarm_sdk/hooks/registry.rb +0 -147
- data/lib/swarm_sdk/hooks/result.rb +0 -150
- data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
- data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
- data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
- data/lib/swarm_sdk/log_collector.rb +0 -227
- data/lib/swarm_sdk/log_stream.rb +0 -127
- data/lib/swarm_sdk/markdown_parser.rb +0 -75
- data/lib/swarm_sdk/model_aliases.json +0 -8
- data/lib/swarm_sdk/models.json +0 -1
- data/lib/swarm_sdk/models.rb +0 -120
- data/lib/swarm_sdk/node_context.rb +0 -245
- data/lib/swarm_sdk/observer/builder.rb +0 -81
- data/lib/swarm_sdk/observer/config.rb +0 -45
- data/lib/swarm_sdk/observer/manager.rb +0 -236
- data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
- data/lib/swarm_sdk/permissions/config.rb +0 -239
- data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
- data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
- data/lib/swarm_sdk/permissions/validator.rb +0 -173
- data/lib/swarm_sdk/permissions_builder.rb +0 -122
- data/lib/swarm_sdk/plugin.rb +0 -309
- data/lib/swarm_sdk/plugin_registry.rb +0 -101
- data/lib/swarm_sdk/proc_helpers.rb +0 -53
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
- data/lib/swarm_sdk/restore_result.rb +0 -65
- data/lib/swarm_sdk/result.rb +0 -123
- data/lib/swarm_sdk/snapshot.rb +0 -156
- data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
- data/lib/swarm_sdk/state_restorer.rb +0 -476
- data/lib/swarm_sdk/state_snapshot.rb +0 -334
- data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
- data/lib/swarm_sdk/swarm/builder.rb +0 -249
- data/lib/swarm_sdk/swarm/executor.rb +0 -213
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
- data/lib/swarm_sdk/swarm.rb +0 -717
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/bash.rb +0 -282
- data/lib/swarm_sdk/tools/clock.rb +0 -44
- data/lib/swarm_sdk/tools/delegate.rb +0 -267
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
- data/lib/swarm_sdk/tools/edit.rb +0 -145
- data/lib/swarm_sdk/tools/glob.rb +0 -166
- data/lib/swarm_sdk/tools/grep.rb +0 -235
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
- data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
- data/lib/swarm_sdk/tools/read.rb +0 -261
- data/lib/swarm_sdk/tools/registry.rb +0 -205
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
- data/lib/swarm_sdk/tools/think.rb +0 -98
- data/lib/swarm_sdk/tools/todo_write.rb +0 -235
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/utils.rb +0 -68
- data/lib/swarm_sdk/validation_result.rb +0 -33
- data/lib/swarm_sdk/version.rb +0 -5
- data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
- data/lib/swarm_sdk/workflow/builder.rb +0 -143
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
- data/lib/swarm_sdk/workflow.rb +0 -554
- 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
|