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,349 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ClaudeSwarm
|
|
4
|
-
class ClaudeCodeExecutor < BaseExecutor
|
|
5
|
-
def execute(prompt, options = {})
|
|
6
|
-
# Log the request
|
|
7
|
-
log_request(prompt)
|
|
8
|
-
|
|
9
|
-
# Build SDK options
|
|
10
|
-
sdk_options = build_sdk_options(prompt, options)
|
|
11
|
-
|
|
12
|
-
# Variables to collect output
|
|
13
|
-
all_messages = []
|
|
14
|
-
result_response = nil
|
|
15
|
-
|
|
16
|
-
# Execute with streaming
|
|
17
|
-
begin
|
|
18
|
-
ClaudeSDK.query(prompt, options: sdk_options) do |message|
|
|
19
|
-
# Convert message to hash for logging
|
|
20
|
-
message_hash = message_to_hash(message)
|
|
21
|
-
all_messages << message_hash
|
|
22
|
-
|
|
23
|
-
# Log streaming event BEFORE we modify anything
|
|
24
|
-
log_streaming_event(message_hash)
|
|
25
|
-
|
|
26
|
-
# Process specific message types
|
|
27
|
-
case message
|
|
28
|
-
when ClaudeSDK::Messages::System
|
|
29
|
-
# Capture session_id from system init
|
|
30
|
-
if message.subtype == "init" && message.data.is_a?(Hash)
|
|
31
|
-
# For init messages, session_id is in the data hash
|
|
32
|
-
session_id = message.data[:session_id] || message.data["session_id"]
|
|
33
|
-
|
|
34
|
-
if session_id
|
|
35
|
-
@session_id = session_id
|
|
36
|
-
write_instance_state
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
when ClaudeSDK::Messages::Assistant
|
|
40
|
-
# Assistant messages only contain content blocks
|
|
41
|
-
# No need to track for result extraction - result comes from Result message
|
|
42
|
-
when ClaudeSDK::Messages::Result
|
|
43
|
-
# Validate that we have actual result content
|
|
44
|
-
if message.result.nil? || (message.result.is_a?(String) && message.result.strip.empty?)
|
|
45
|
-
raise ExecutionError, "Claude SDK returned an empty result. The agent completed execution but provided no response content."
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Build result response in expected format
|
|
49
|
-
result_response = {
|
|
50
|
-
"type" => "result",
|
|
51
|
-
"subtype" => message.subtype || "success",
|
|
52
|
-
"cost_usd" => message.total_cost_usd,
|
|
53
|
-
"is_error" => message.is_error || false,
|
|
54
|
-
"duration_ms" => message.duration_ms,
|
|
55
|
-
"result" => message.result, # Result text is directly in message.result
|
|
56
|
-
"total_cost" => message.total_cost_usd,
|
|
57
|
-
"session_id" => message.session_id,
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
rescue StandardError => e
|
|
62
|
-
logger.error { "Execution error for #{@instance_name}: #{e.class} - #{e.message}" }
|
|
63
|
-
logger.error { "Backtrace: #{e.backtrace.join("\n")}" }
|
|
64
|
-
raise ExecutionError, "Claude Code execution failed: #{e.message}"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Ensure we got a result
|
|
68
|
-
raise ParseError, "No result found in SDK response" unless result_response
|
|
69
|
-
|
|
70
|
-
# Write session JSON log
|
|
71
|
-
all_messages.each do |msg|
|
|
72
|
-
append_to_session_json(msg)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
result_response
|
|
76
|
-
rescue StandardError => e
|
|
77
|
-
logger.error { "Unexpected error for #{@instance_name}: #{e.class} - #{e.message}" }
|
|
78
|
-
logger.error { "Backtrace: #{e.backtrace.join("\n")}" }
|
|
79
|
-
raise
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
def write_instance_state
|
|
85
|
-
return unless @instance_id && @session_id
|
|
86
|
-
|
|
87
|
-
state_dir = File.join(@session_path, "state")
|
|
88
|
-
FileUtils.mkdir_p(state_dir)
|
|
89
|
-
|
|
90
|
-
state_file = File.join(state_dir, "#{@instance_id}.json")
|
|
91
|
-
state_data = {
|
|
92
|
-
instance_name: @instance_name,
|
|
93
|
-
instance_id: @instance_id,
|
|
94
|
-
claude_session_id: @session_id,
|
|
95
|
-
status: "active",
|
|
96
|
-
updated_at: Time.now.iso8601,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
JsonHandler.write_file!(state_file, state_data)
|
|
100
|
-
logger.info { "Wrote instance state for #{@instance_name} (#{@instance_id}) with session ID: #{@session_id}" }
|
|
101
|
-
rescue StandardError => e
|
|
102
|
-
logger.error { "Failed to write instance state for #{@instance_name} (#{@instance_id}): #{e.message}" }
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def log_streaming_event(event)
|
|
106
|
-
append_to_session_json(event)
|
|
107
|
-
|
|
108
|
-
return log_system_message(event) if event["type"] == "system"
|
|
109
|
-
|
|
110
|
-
# Add specific details based on event type
|
|
111
|
-
case event["type"]
|
|
112
|
-
when "assistant"
|
|
113
|
-
log_assistant_message(event["message"])
|
|
114
|
-
when "user"
|
|
115
|
-
log_user_message(event["message"]["content"])
|
|
116
|
-
when "result"
|
|
117
|
-
log_response(event)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def log_system_message(event)
|
|
122
|
-
logger.debug { "SYSTEM: #{JsonHandler.pretty_generate!(event)}" }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def log_assistant_message(msg)
|
|
126
|
-
# Assistant messages don't have stop_reason in SDK - they only have content
|
|
127
|
-
content = msg["content"]
|
|
128
|
-
logger.debug { "ASSISTANT: #{JsonHandler.pretty_generate!(content)}" } if content
|
|
129
|
-
|
|
130
|
-
# Log tool calls
|
|
131
|
-
tool_calls = content&.select { |c| c["type"] == "tool_use" } || []
|
|
132
|
-
tool_calls.each do |tool_call|
|
|
133
|
-
arguments = tool_call["input"].to_json
|
|
134
|
-
arguments = "#{arguments[0..300]} ...}" if arguments.length > 300
|
|
135
|
-
|
|
136
|
-
logger.info do
|
|
137
|
-
"Tool call from #{instance_info} -> Tool: #{tool_call["name"]}, ID: #{tool_call["id"]}, Arguments: #{arguments}"
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Log thinking text
|
|
142
|
-
text = content&.select { |c| c["type"] == "text" } || []
|
|
143
|
-
text.each do |t|
|
|
144
|
-
logger.info { "#{instance_info} is thinking:\n---\n#{t["text"]}\n---" }
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def log_user_message(content)
|
|
149
|
-
logger.debug { "USER: #{JsonHandler.pretty_generate!(content)}" }
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def build_sdk_options(prompt, options)
|
|
153
|
-
# Map CLI options to SDK options
|
|
154
|
-
sdk_options = ClaudeSDK::ClaudeCodeOptions.new
|
|
155
|
-
|
|
156
|
-
# Basic options
|
|
157
|
-
# Only set model if ANTHROPIC_MODEL env var is not set
|
|
158
|
-
sdk_options.model = @model if @model && !ENV["ANTHROPIC_MODEL"]
|
|
159
|
-
sdk_options.cwd = @working_directory
|
|
160
|
-
sdk_options.resume = @session_id if @session_id && !options[:new_session]
|
|
161
|
-
|
|
162
|
-
# Permission mode
|
|
163
|
-
if @vibe
|
|
164
|
-
sdk_options.permission_mode = ClaudeSDK::PermissionMode::BYPASS_PERMISSIONS
|
|
165
|
-
else
|
|
166
|
-
# Build allowed tools list including MCP connections
|
|
167
|
-
allowed_tools = options[:allowed_tools] ? Array(options[:allowed_tools]).dup : []
|
|
168
|
-
|
|
169
|
-
# Add mcp__instance_name for each connection if we have instance info
|
|
170
|
-
options[:connections]&.each do |connection_name|
|
|
171
|
-
allowed_tools << "mcp__#{connection_name}"
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# Set allowed and disallowed tools
|
|
175
|
-
sdk_options.allowed_tools = allowed_tools if allowed_tools.any?
|
|
176
|
-
sdk_options.disallowed_tools = Array(options[:disallowed_tools]) if options[:disallowed_tools]
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# System prompt
|
|
180
|
-
sdk_options.append_system_prompt = options[:system_prompt] if options[:system_prompt]
|
|
181
|
-
|
|
182
|
-
# MCP configuration
|
|
183
|
-
if @mcp_config
|
|
184
|
-
sdk_options.mcp_servers = parse_mcp_config(@mcp_config)
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# Handle additional directories by adding them to MCP servers
|
|
188
|
-
if @additional_directories.any?
|
|
189
|
-
setup_additional_directories_mcp(sdk_options)
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Add settings file path if it exists
|
|
193
|
-
settings_file = File.join(@session_path, "#{@instance_name}_settings.json")
|
|
194
|
-
sdk_options.settings = settings_file if File.exist?(settings_file)
|
|
195
|
-
|
|
196
|
-
sdk_options
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def parse_mcp_config(config_path)
|
|
200
|
-
# Parse MCP JSON config file and convert to SDK format
|
|
201
|
-
config = JsonHandler.parse_file!(config_path)
|
|
202
|
-
mcp_servers = {}
|
|
203
|
-
|
|
204
|
-
config["mcpServers"]&.each do |name, server_config|
|
|
205
|
-
server_type = server_config["type"] || "stdio"
|
|
206
|
-
|
|
207
|
-
mcp_servers[name] = case server_type
|
|
208
|
-
when "stdio"
|
|
209
|
-
ClaudeSDK::McpServerConfig::StdioServer.new(
|
|
210
|
-
command: server_config["command"],
|
|
211
|
-
args: server_config["args"] || [],
|
|
212
|
-
env: server_config["env"] || {},
|
|
213
|
-
)
|
|
214
|
-
when "sse"
|
|
215
|
-
ClaudeSDK::McpServerConfig::SSEServer.new(
|
|
216
|
-
url: server_config["url"],
|
|
217
|
-
headers: server_config["headers"] || {},
|
|
218
|
-
)
|
|
219
|
-
when "http"
|
|
220
|
-
ClaudeSDK::McpServerConfig::HttpServer.new(
|
|
221
|
-
url: server_config["url"],
|
|
222
|
-
headers: server_config["headers"] || {},
|
|
223
|
-
)
|
|
224
|
-
else
|
|
225
|
-
logger.warn { "Unsupported MCP server type: #{server_type} for server: #{name}" }
|
|
226
|
-
nil
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
mcp_servers.compact
|
|
231
|
-
rescue StandardError => e
|
|
232
|
-
logger.error { "Failed to parse MCP config: #{e.message}" }
|
|
233
|
-
{}
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def setup_additional_directories_mcp(sdk_options)
|
|
237
|
-
# Workaround for --add-dir: add file system MCP servers for additional directories
|
|
238
|
-
sdk_options.mcp_servers ||= {}
|
|
239
|
-
|
|
240
|
-
@additional_directories.each do |dir|
|
|
241
|
-
# This is a placeholder - the SDK doesn't directly support file system servers
|
|
242
|
-
# You would need to implement a proper MCP server that provides file access
|
|
243
|
-
logger.warn { "Additional directories not fully supported: #{dir}" }
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def message_to_hash(message)
|
|
248
|
-
# Convert SDK message objects to hash format matching CLI JSON output
|
|
249
|
-
case message
|
|
250
|
-
when ClaudeSDK::Messages::System
|
|
251
|
-
# System messages have subtype and data attributes
|
|
252
|
-
# The data hash contains the actual information from the CLI
|
|
253
|
-
hash = {
|
|
254
|
-
"type" => "system",
|
|
255
|
-
"subtype" => message.subtype,
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
# Include the data hash if it exists - this is where CLI puts info like session_id, tools, etc.
|
|
259
|
-
if message.data.is_a?(Hash)
|
|
260
|
-
# For "init" subtype, extract session_id and tools from data
|
|
261
|
-
if message.subtype == "init"
|
|
262
|
-
hash["session_id"] = message.data[:session_id] || message.data["session_id"]
|
|
263
|
-
hash["tools"] = message.data[:tools] || message.data["tools"]
|
|
264
|
-
end
|
|
265
|
-
# You can add other relevant data fields as needed
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
hash.compact
|
|
269
|
-
when ClaudeSDK::Messages::Assistant
|
|
270
|
-
# Assistant messages only have content attribute
|
|
271
|
-
{
|
|
272
|
-
"type" => "assistant",
|
|
273
|
-
"message" => {
|
|
274
|
-
"type" => "message",
|
|
275
|
-
"role" => "assistant",
|
|
276
|
-
"content" => content_blocks_to_hash(message.content),
|
|
277
|
-
},
|
|
278
|
-
"session_id" => @session_id,
|
|
279
|
-
}
|
|
280
|
-
when ClaudeSDK::Messages::User
|
|
281
|
-
# User messages only have content attribute (a string)
|
|
282
|
-
{
|
|
283
|
-
"type" => "user",
|
|
284
|
-
"message" => {
|
|
285
|
-
"type" => "message",
|
|
286
|
-
"role" => "user",
|
|
287
|
-
"content" => message.content,
|
|
288
|
-
},
|
|
289
|
-
"session_id" => @session_id,
|
|
290
|
-
}
|
|
291
|
-
when ClaudeSDK::Messages::Result
|
|
292
|
-
# Result messages have multiple attributes
|
|
293
|
-
{
|
|
294
|
-
"type" => "result",
|
|
295
|
-
"subtype" => message.subtype || "success",
|
|
296
|
-
"cost_usd" => message.total_cost_usd,
|
|
297
|
-
"is_error" => message.is_error || false,
|
|
298
|
-
"duration_ms" => message.duration_ms,
|
|
299
|
-
"duration_api_ms" => message.duration_api_ms,
|
|
300
|
-
"num_turns" => message.num_turns,
|
|
301
|
-
"result" => message.result, # Result text is in message.result, not from content
|
|
302
|
-
"total_cost" => message.total_cost_usd,
|
|
303
|
-
"total_cost_usd" => message.total_cost_usd,
|
|
304
|
-
"session_id" => message.session_id,
|
|
305
|
-
"usage" => message.usage,
|
|
306
|
-
}.compact
|
|
307
|
-
else
|
|
308
|
-
# Fallback for unknown message types
|
|
309
|
-
begin
|
|
310
|
-
message.to_h
|
|
311
|
-
rescue
|
|
312
|
-
{ "type" => "unknown", "data" => message.to_s }
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
def content_blocks_to_hash(content)
|
|
318
|
-
return [] unless content
|
|
319
|
-
|
|
320
|
-
content.map do |block|
|
|
321
|
-
case block
|
|
322
|
-
when ClaudeSDK::ContentBlock::Text
|
|
323
|
-
{ "type" => "text", "text" => block.text }
|
|
324
|
-
when ClaudeSDK::ContentBlock::ToolUse
|
|
325
|
-
{
|
|
326
|
-
"type" => "tool_use",
|
|
327
|
-
"id" => block.id,
|
|
328
|
-
"name" => block.name,
|
|
329
|
-
"input" => block.input,
|
|
330
|
-
}
|
|
331
|
-
when ClaudeSDK::ContentBlock::ToolResult
|
|
332
|
-
{
|
|
333
|
-
"type" => "tool_result",
|
|
334
|
-
"tool_use_id" => block.tool_use_id,
|
|
335
|
-
"content" => block.content,
|
|
336
|
-
"is_error" => block.is_error,
|
|
337
|
-
}
|
|
338
|
-
else
|
|
339
|
-
# Fallback
|
|
340
|
-
begin
|
|
341
|
-
block.to_h
|
|
342
|
-
rescue
|
|
343
|
-
{ "type" => "unknown", "data" => block.to_s }
|
|
344
|
-
end
|
|
345
|
-
end
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
end
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ClaudeSwarm
|
|
4
|
-
class ClaudeMcpServer
|
|
5
|
-
# Class variables to share state with tool classes
|
|
6
|
-
class << self
|
|
7
|
-
attr_accessor :executor, :instance_config, :logger, :session_path, :calling_instance, :calling_instance_id
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def initialize(instance_config, calling_instance:, calling_instance_id: nil, debug: false)
|
|
11
|
-
@instance_config = instance_config
|
|
12
|
-
@calling_instance = calling_instance
|
|
13
|
-
@calling_instance_id = calling_instance_id
|
|
14
|
-
|
|
15
|
-
# Create appropriate executor based on provider
|
|
16
|
-
common_params = {
|
|
17
|
-
working_directory: instance_config[:directory],
|
|
18
|
-
model: instance_config[:model],
|
|
19
|
-
mcp_config: instance_config[:mcp_config_path],
|
|
20
|
-
vibe: instance_config[:vibe],
|
|
21
|
-
instance_name: instance_config[:name],
|
|
22
|
-
instance_id: instance_config[:instance_id],
|
|
23
|
-
calling_instance: calling_instance,
|
|
24
|
-
calling_instance_id: calling_instance_id,
|
|
25
|
-
claude_session_id: instance_config[:claude_session_id],
|
|
26
|
-
additional_directories: instance_config[:directories][1..] || [],
|
|
27
|
-
debug: debug,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@executor = if instance_config[:provider] == "openai"
|
|
31
|
-
OpenAI::Executor.new(
|
|
32
|
-
**common_params,
|
|
33
|
-
# OpenAI-specific parameters
|
|
34
|
-
temperature: instance_config[:temperature],
|
|
35
|
-
api_version: instance_config[:api_version],
|
|
36
|
-
openai_token_env: instance_config[:openai_token_env],
|
|
37
|
-
base_url: instance_config[:base_url],
|
|
38
|
-
reasoning_effort: instance_config[:reasoning_effort],
|
|
39
|
-
zdr: instance_config[:zdr],
|
|
40
|
-
)
|
|
41
|
-
else
|
|
42
|
-
# Default Claude behavior - always use SDK
|
|
43
|
-
ClaudeCodeExecutor.new(**common_params)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Set class variables so tools can access them
|
|
47
|
-
self.class.executor = @executor
|
|
48
|
-
self.class.instance_config = @instance_config
|
|
49
|
-
self.class.logger = @executor.logger
|
|
50
|
-
self.class.session_path = @executor.session_path
|
|
51
|
-
self.class.calling_instance = @calling_instance
|
|
52
|
-
self.class.calling_instance_id = @calling_instance_id
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def start
|
|
56
|
-
server = FastMcp::Server.new(
|
|
57
|
-
name: @instance_config[:name],
|
|
58
|
-
version: "1.0.0",
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# Set dynamic description for TaskTool based on instance config
|
|
62
|
-
thinking_info = " Thinking budget levels: \"think\" < \"think hard\" < \"think harder\" < \"ultrathink\"."
|
|
63
|
-
if @instance_config[:description]
|
|
64
|
-
Tools::TaskTool.description("Execute a task using Agent #{@instance_config[:name]}. #{@instance_config[:description]} #{thinking_info}")
|
|
65
|
-
else
|
|
66
|
-
Tools::TaskTool.description("Execute a task using Agent #{@instance_config[:name]}. #{thinking_info}")
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Register tool classes (not instances)
|
|
70
|
-
server.register_tool(Tools::TaskTool)
|
|
71
|
-
server.register_tool(Tools::SessionInfoTool)
|
|
72
|
-
server.register_tool(Tools::ResetSessionTool)
|
|
73
|
-
|
|
74
|
-
# Start the stdio server
|
|
75
|
-
server.start
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|