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,230 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ClaudeSwarm
4
- class McpGenerator
5
- CLAUDE_MCP_SERVER_CONFIG = {
6
- "type" => "stdio",
7
- "command" => "claude",
8
- "args" => ["mcp", "serve"],
9
- }.freeze
10
-
11
- def initialize(configuration, vibe: false, restore_session_path: nil)
12
- @config = configuration
13
- @vibe = vibe
14
- @restore_session_path = restore_session_path
15
- @session_path = nil # Will be set when needed
16
- @instance_ids = {} # Store instance IDs for all instances
17
- @restore_states = {} # Store loaded state data during restoration
18
- end
19
-
20
- def generate_all
21
- ensure_swarm_directory
22
-
23
- if @restore_session_path
24
- # Load existing instance IDs and states from state files
25
- load_instance_states
26
- else
27
- # Generate new instance IDs
28
- @config.instances.each_key do |name|
29
- @instance_ids[name] = "#{name}_#{SecureRandom.hex(4)}"
30
- end
31
- end
32
-
33
- @config.instances.each do |name, instance|
34
- generate_mcp_config(name, instance)
35
- end
36
- end
37
-
38
- def mcp_config_path(instance_name)
39
- File.join(session_path, "#{instance_name}.mcp.json")
40
- end
41
-
42
- private
43
-
44
- def session_path
45
- @session_path ||= SessionPath.from_env
46
- end
47
-
48
- def ensure_swarm_directory
49
- # Session directory is already created by orchestrator
50
- # Just ensure it exists
51
- SessionPath.ensure_directory(session_path)
52
- end
53
-
54
- def generate_mcp_config(name, instance)
55
- mcp_servers = {}
56
-
57
- # Add configured MCP servers
58
- instance[:mcps].each do |mcp|
59
- mcp_servers[mcp["name"]] = build_mcp_server_config(mcp)
60
- end
61
-
62
- # Add connection MCPs for other instances
63
- instance[:connections].each do |connection_name|
64
- connected_instance = @config.instances[connection_name]
65
- mcp_servers[connection_name] = build_instance_mcp_config(
66
- connection_name,
67
- connected_instance,
68
- calling_instance: name,
69
- calling_instance_id: @instance_ids[name],
70
- )
71
- end
72
-
73
- # Add Claude tools MCP server for OpenAI instances
74
- mcp_servers["claude_tools"] = CLAUDE_MCP_SERVER_CONFIG.dup if instance[:provider] == "openai"
75
-
76
- config = {
77
- "instance_id" => @instance_ids[name],
78
- "instance_name" => name,
79
- "mcpServers" => mcp_servers,
80
- }
81
-
82
- JsonHandler.write_file!(mcp_config_path(name), config)
83
- end
84
-
85
- def build_mcp_server_config(mcp)
86
- case mcp["type"]
87
- when "stdio"
88
- {
89
- "type" => "stdio",
90
- "command" => mcp["command"],
91
- "args" => mcp["args"] || [],
92
- }.tap do |config|
93
- config["env"] = mcp["env"] if mcp["env"]
94
- end
95
- when "sse", "http"
96
- {
97
- "type" => mcp["type"],
98
- "url" => mcp["url"],
99
- }.tap do |config|
100
- config["headers"] = mcp["headers"] if mcp["headers"]
101
- end
102
- end
103
- end
104
-
105
- def build_instance_mcp_config(name, instance, calling_instance:, calling_instance_id:)
106
- # Get the path to the claude-swarm executable
107
- exe_path = "claude-swarm"
108
-
109
- # Build command-line arguments for Thor
110
- args = [
111
- "mcp-serve",
112
- "--name",
113
- name,
114
- "--directory",
115
- instance[:directory],
116
- "--model",
117
- instance[:model],
118
- ]
119
-
120
- # Add directories array if we have multiple directories
121
- args.push("--directories", *instance[:directories]) if instance[:directories] && instance[:directories].size > 1
122
-
123
- # Add optional arguments
124
- # Handle prompt_file by reading the file contents
125
- if instance[:prompt_file]
126
- prompt_file_path = File.join(@config.root_directory, instance[:prompt_file])
127
- if File.exist?(prompt_file_path)
128
- prompt_content = File.read(prompt_file_path)
129
- args.push("--prompt", prompt_content)
130
- end
131
- elsif instance[:prompt]
132
- args.push("--prompt", instance[:prompt])
133
- end
134
-
135
- args.push("--description", instance[:description]) if instance[:description]
136
-
137
- args.push("--allowed-tools", instance[:allowed_tools].join(",")) if instance[:allowed_tools] && !instance[:allowed_tools].empty?
138
-
139
- args.push("--disallowed-tools", instance[:disallowed_tools].join(",")) if instance[:disallowed_tools] && !instance[:disallowed_tools].empty?
140
-
141
- args.push("--connections", instance[:connections].join(",")) if instance[:connections] && !instance[:connections].empty?
142
-
143
- args.push("--mcp-config-path", mcp_config_path(name))
144
-
145
- args.push("--calling-instance", calling_instance) if calling_instance
146
-
147
- args.push("--calling-instance-id", calling_instance_id) if calling_instance_id
148
-
149
- args.push("--instance-id", @instance_ids[name]) if @instance_ids[name]
150
-
151
- args.push("--vibe") if @vibe || instance[:vibe]
152
-
153
- # Add provider-specific parameters
154
- if instance[:provider]
155
- args.push("--provider", instance[:provider])
156
-
157
- # Add OpenAI-specific parameters
158
- if instance[:provider] == "openai"
159
- args.push("--reasoning-effort", instance[:reasoning_effort]) if instance[:reasoning_effort]
160
- args.push("--temperature", instance[:temperature].to_s) if instance[:temperature]
161
- args.push("--api-version", instance[:api_version]) if instance[:api_version]
162
- args.push("--openai-token-env", instance[:openai_token_env]) if instance[:openai_token_env]
163
- args.push("--base-url", instance[:base_url]) if instance[:base_url]
164
- args.push("--zdr", instance[:zdr].to_s) if instance.key?(:zdr)
165
- end
166
- end
167
-
168
- # Add claude session ID if restoring
169
- if @restore_states[name.to_s]
170
- claude_session_id = @restore_states[name.to_s]["claude_session_id"]
171
- args.push("--claude-session-id", claude_session_id) if claude_session_id
172
- end
173
-
174
- # Capture environment variables needed for running claude-swarm
175
- # We intentionally exclude Bundler variables to ensure we use the system-installed gem
176
- required_env = {}
177
-
178
- # Claude Swarm-specific variables (always needed)
179
- ENV.each do |k, v|
180
- required_env[k] = v if k.start_with?("CLAUDE_SWARM_")
181
- end
182
-
183
- # Ruby-specific variables that MCP servers need
184
- # Exclude RUBYOPT and RUBYLIB to avoid Bundler interference
185
- [
186
- "RUBY_ROOT",
187
- "RUBY_ENGINE",
188
- "RUBY_VERSION",
189
- "GEM_ROOT",
190
- "GEM_HOME",
191
- "GEM_PATH",
192
- "PATH",
193
- ].each do |key|
194
- required_env[key] = ENV[key] if ENV[key]
195
- end
196
-
197
- config = {
198
- "type" => "stdio",
199
- "command" => exe_path,
200
- "args" => args,
201
- }
202
-
203
- # Add required environment variables if any exist
204
- config["env"] = required_env unless required_env.empty?
205
-
206
- config
207
- end
208
-
209
- def load_instance_states
210
- state_dir = File.join(@restore_session_path, "state")
211
- return unless Dir.exist?(state_dir)
212
-
213
- Dir.glob(File.join(state_dir, "*.json")).each do |state_file|
214
- data = JsonHandler.parse_file!(state_file)
215
- instance_name = data["instance_name"]
216
- instance_id = data["instance_id"]
217
-
218
- # Check both string and symbol keys since config instances might have either
219
- if instance_name && (@config.instances.key?(instance_name) || @config.instances.key?(instance_name.to_sym))
220
- # Store with the same key type as in @config.instances
221
- key = @config.instances.key?(instance_name) ? instance_name : instance_name.to_sym
222
- @instance_ids[key] = instance_id
223
- @restore_states[instance_name] = data
224
- end
225
- rescue StandardError
226
- # Skip invalid state files
227
- end
228
- end
229
- end
230
- end
@@ -1,256 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ClaudeSwarm
4
- module OpenAI
5
- class ChatCompletion
6
- MAX_TURNS_WITH_TOOLS = 100_000 # virtually infinite
7
-
8
- def initialize(openai_client:, mcp_client:, available_tools:, executor:, instance_name:, model:, temperature: nil, reasoning_effort: nil, zdr: false)
9
- @openai_client = openai_client
10
- @mcp_client = mcp_client
11
- @available_tools = available_tools
12
- @executor = executor
13
- @instance_name = instance_name
14
- @model = model
15
- @temperature = temperature
16
- @reasoning_effort = reasoning_effort
17
- @zdr = zdr # Not used in chat_completion API, but kept for compatibility
18
- @conversation_messages = []
19
- end
20
-
21
- def execute(prompt, options = {})
22
- # Build messages array
23
- messages = build_messages(prompt, options)
24
-
25
- # Process chat with recursive tool handling
26
- result = process_chat_completion(messages)
27
-
28
- # Update conversation state
29
- @conversation_messages = messages
30
-
31
- result
32
- end
33
-
34
- def reset_session
35
- @conversation_messages = []
36
- end
37
-
38
- private
39
-
40
- def build_messages(prompt, options)
41
- messages = []
42
-
43
- # Add system prompt if provided
44
- system_prompt = options[:system_prompt]
45
- if system_prompt && @conversation_messages.empty?
46
- messages << { role: "system", content: system_prompt }
47
- elsif !@conversation_messages.empty?
48
- # Use existing conversation
49
- messages = @conversation_messages.dup
50
- end
51
-
52
- # Add user message
53
- messages << { role: "user", content: prompt }
54
-
55
- messages
56
- end
57
-
58
- def process_chat_completion(messages, depth = 0)
59
- # Prevent infinite recursion
60
- if depth > MAX_TURNS_WITH_TOOLS
61
- @executor.logger.error { "Maximum recursion depth reached in tool execution" }
62
- return "Error: Maximum tool call depth exceeded"
63
- end
64
-
65
- # Build parameters
66
- parameters = {
67
- model: @model,
68
- messages: messages,
69
- }
70
-
71
- parameters[:temperature] = @temperature if @temperature
72
- parameters[:reasoning_effort] = @reasoning_effort if @reasoning_effort
73
-
74
- # Add tools if available
75
- parameters[:tools] = @mcp_client.to_openai_tools if @available_tools&.any? && @mcp_client
76
-
77
- # Log the request parameters
78
- @executor.logger.info { "Chat API Request (depth=#{depth}): #{JsonHandler.pretty_generate!(parameters)}" }
79
-
80
- # Append to session JSON
81
- append_to_session_json({
82
- type: "openai_request",
83
- api: "chat",
84
- depth: depth,
85
- parameters: parameters,
86
- })
87
-
88
- # Make the API call without streaming
89
- begin
90
- response = @openai_client.chat(parameters: parameters)
91
- rescue StandardError => e
92
- @executor.logger.error { "Chat API error: #{e.class} - #{e.message}" }
93
- @executor.logger.error { "Request parameters: #{JsonHandler.pretty_generate!(parameters)}" }
94
-
95
- # Try to extract and log the response body for better debugging
96
- if e.respond_to?(:response)
97
- begin
98
- error_body = e.response[:body]
99
- @executor.logger.error { "Error response body: #{error_body}" }
100
- rescue StandardError => parse_error
101
- @executor.logger.error { "Could not parse error response: #{parse_error.message}" }
102
- end
103
- end
104
-
105
- # Log error to session JSON
106
- append_to_session_json({
107
- type: "openai_error",
108
- api: "chat",
109
- depth: depth,
110
- error: {
111
- class: e.class.to_s,
112
- message: e.message,
113
- response_body: e.respond_to?(:response) ? e.response[:body] : nil,
114
- backtrace: e.backtrace.first(5),
115
- },
116
- })
117
-
118
- return "Error calling OpenAI chat API: #{e.message}"
119
- end
120
-
121
- # Log the response
122
- @executor.logger.info { "Chat API Response (depth=#{depth}): #{JsonHandler.pretty_generate!(response)}" }
123
-
124
- # Append to session JSON
125
- append_to_session_json({
126
- type: "openai_response",
127
- api: "chat",
128
- depth: depth,
129
- response: response,
130
- })
131
-
132
- # Extract the message from the response
133
- message = response.dig("choices", 0, "message")
134
-
135
- if message.nil?
136
- @executor.logger.error { "No message in response: #{response.inspect}" }
137
- return "Error: No response from OpenAI"
138
- end
139
-
140
- # Check if there are tool calls
141
- if message["tool_calls"]
142
- # Add the assistant message with tool calls
143
- messages << {
144
- role: "assistant",
145
- content: nil,
146
- tool_calls: message["tool_calls"],
147
- }
148
-
149
- # Execute tools and collect results
150
- execute_and_append_tool_results(message["tool_calls"], messages)
151
-
152
- # Recursively process the next response
153
- process_chat_completion(messages, depth + 1)
154
- else
155
- # Regular text response - this is the final response
156
- response_text = message["content"] || ""
157
- messages << { role: "assistant", content: response_text }
158
- response_text
159
- end
160
- end
161
-
162
- def execute_and_append_tool_results(tool_calls, messages)
163
- # Log tool calls
164
- @executor.logger.info { "Executing tool calls: #{JsonHandler.pretty_generate!(tool_calls)}" }
165
-
166
- # Append to session JSON
167
- append_to_session_json({
168
- type: "tool_calls",
169
- api: "chat",
170
- tool_calls: tool_calls,
171
- })
172
-
173
- # Execute tool calls in parallel threads
174
- threads = tool_calls.map do |tool_call|
175
- Thread.new do
176
- tool_name = tool_call.dig("function", "name")
177
- tool_args_str = tool_call.dig("function", "arguments")
178
-
179
- begin
180
- # Parse arguments
181
- tool_args = tool_args_str.is_a?(String) ? JsonHandler.parse!(tool_args_str) : tool_args_str
182
-
183
- # Log tool execution
184
- @executor.logger.info { "Executing tool: #{tool_name} with args: #{JsonHandler.pretty_generate!(tool_args)}" }
185
-
186
- # Execute tool via MCP
187
- result = @mcp_client.call_tool(tool_name, tool_args)
188
-
189
- # Log result
190
- @executor.logger.info { "Tool result for #{tool_name}: #{result}" }
191
-
192
- # Append to session JSON
193
- append_to_session_json({
194
- type: "tool_execution",
195
- tool_name: tool_name,
196
- arguments: tool_args,
197
- result: result.to_s,
198
- })
199
-
200
- # Return success result
201
- {
202
- success: true,
203
- tool_call_id: tool_call["id"],
204
- role: "tool",
205
- name: tool_name,
206
- content: result.to_s,
207
- }
208
- rescue StandardError => e
209
- @executor.logger.error { "Tool execution failed for #{tool_name}: #{e.message}" }
210
- @executor.logger.error { e.backtrace.join("\n") }
211
-
212
- # Append error to session JSON
213
- append_to_session_json({
214
- type: "tool_error",
215
- tool_name: tool_name,
216
- arguments: tool_args,
217
- error: {
218
- class: e.class.to_s,
219
- message: e.message,
220
- backtrace: e.backtrace.first(5),
221
- },
222
- })
223
-
224
- # Return error result
225
- {
226
- success: false,
227
- tool_call_id: tool_call["id"],
228
- role: "tool",
229
- name: tool_name,
230
- content: "Error: #{e.message}",
231
- }
232
- end
233
- end
234
- end
235
-
236
- # Collect results from all threads
237
- tool_results = threads.map(&:value)
238
-
239
- # Add all tool results to messages
240
- tool_results.each do |result|
241
- messages << {
242
- tool_call_id: result[:tool_call_id],
243
- role: result[:role],
244
- name: result[:name],
245
- content: result[:content],
246
- }
247
- end
248
- end
249
-
250
- def append_to_session_json(event)
251
- # Delegate to the executor's log method
252
- @executor.log(event) if @executor.respond_to?(:log)
253
- end
254
- end
255
- end
256
- end