swarm_memory 2.1.4 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. data/lib/swarm_memory.rb +7 -2
  4. metadata +6 -185
  5. data/lib/claude_swarm/base_executor.rb +0 -133
  6. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  7. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  8. data/lib/claude_swarm/cli.rb +0 -697
  9. data/lib/claude_swarm/commands/ps.rb +0 -215
  10. data/lib/claude_swarm/commands/show.rb +0 -139
  11. data/lib/claude_swarm/configuration.rb +0 -373
  12. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  13. data/lib/claude_swarm/json_handler.rb +0 -91
  14. data/lib/claude_swarm/mcp_generator.rb +0 -243
  15. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  16. data/lib/claude_swarm/openai/executor.rb +0 -256
  17. data/lib/claude_swarm/openai/responses.rb +0 -319
  18. data/lib/claude_swarm/orchestrator.rb +0 -878
  19. data/lib/claude_swarm/process_tracker.rb +0 -78
  20. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  21. data/lib/claude_swarm/session_path.rb +0 -42
  22. data/lib/claude_swarm/settings_generator.rb +0 -77
  23. data/lib/claude_swarm/system_utils.rb +0 -46
  24. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  25. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  27. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  28. data/lib/claude_swarm/version.rb +0 -5
  29. data/lib/claude_swarm/worktree_manager.rb +0 -475
  30. data/lib/claude_swarm/yaml_loader.rb +0 -22
  31. data/lib/claude_swarm.rb +0 -67
  32. data/lib/swarm_cli/cli.rb +0 -201
  33. data/lib/swarm_cli/command_registry.rb +0 -61
  34. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  35. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  36. data/lib/swarm_cli/commands/migrate.rb +0 -55
  37. data/lib/swarm_cli/commands/run.rb +0 -173
  38. data/lib/swarm_cli/config_loader.rb +0 -98
  39. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  40. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  41. data/lib/swarm_cli/interactive_repl.rb +0 -924
  42. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  43. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  44. data/lib/swarm_cli/migrate_options.rb +0 -54
  45. data/lib/swarm_cli/migrator.rb +0 -132
  46. data/lib/swarm_cli/options.rb +0 -151
  47. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  48. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  49. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  50. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  51. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  52. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  53. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  54. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  55. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  56. data/lib/swarm_cli/ui/icons.rb +0 -36
  57. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  58. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  59. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  60. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  61. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  62. data/lib/swarm_cli/version.rb +0 -5
  63. data/lib/swarm_cli.rb +0 -46
  64. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  65. data/lib/swarm_sdk/agent/builder.rb +0 -552
  66. data/lib/swarm_sdk/agent/chat.rb +0 -774
  67. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  68. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  69. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  70. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  71. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  72. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  73. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  75. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  76. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  77. data/lib/swarm_sdk/agent/context.rb +0 -116
  78. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  79. data/lib/swarm_sdk/agent/definition.rb +0 -477
  80. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  81. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  82. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  83. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  84. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  85. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  86. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  87. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  88. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  89. data/lib/swarm_sdk/configuration.rb +0 -135
  90. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  91. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  92. data/lib/swarm_sdk/context_compactor.rb +0 -335
  93. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  94. data/lib/swarm_sdk/context_management/context.rb +0 -328
  95. data/lib/swarm_sdk/defaults.rb +0 -196
  96. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  97. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  98. data/lib/swarm_sdk/hooks/context.rb +0 -197
  99. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  100. data/lib/swarm_sdk/hooks/error.rb +0 -29
  101. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  102. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  103. data/lib/swarm_sdk/hooks/result.rb +0 -150
  104. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  105. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  106. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  107. data/lib/swarm_sdk/log_collector.rb +0 -227
  108. data/lib/swarm_sdk/log_stream.rb +0 -127
  109. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  110. data/lib/swarm_sdk/model_aliases.json +0 -8
  111. data/lib/swarm_sdk/models.json +0 -1
  112. data/lib/swarm_sdk/models.rb +0 -120
  113. data/lib/swarm_sdk/node_context.rb +0 -245
  114. data/lib/swarm_sdk/observer/builder.rb +0 -81
  115. data/lib/swarm_sdk/observer/config.rb +0 -45
  116. data/lib/swarm_sdk/observer/manager.rb +0 -236
  117. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  118. data/lib/swarm_sdk/permissions/config.rb +0 -239
  119. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  120. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  121. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  122. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  123. data/lib/swarm_sdk/plugin.rb +0 -309
  124. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  125. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  126. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  127. data/lib/swarm_sdk/restore_result.rb +0 -65
  128. data/lib/swarm_sdk/result.rb +0 -123
  129. data/lib/swarm_sdk/snapshot.rb +0 -156
  130. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  131. data/lib/swarm_sdk/state_restorer.rb +0 -476
  132. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  133. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  134. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  135. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  136. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  137. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  138. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  139. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  140. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  141. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  142. data/lib/swarm_sdk/swarm.rb +0 -717
  143. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  144. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  145. data/lib/swarm_sdk/tools/bash.rb +0 -282
  146. data/lib/swarm_sdk/tools/clock.rb +0 -44
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  160. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  161. data/lib/swarm_sdk/tools/read.rb +0 -261
  162. data/lib/swarm_sdk/tools/registry.rb +0 -205
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  166. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  167. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  168. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  169. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  170. data/lib/swarm_sdk/tools/think.rb +0 -98
  171. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  172. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  173. data/lib/swarm_sdk/tools/write.rb +0 -112
  174. data/lib/swarm_sdk/utils.rb +0 -68
  175. data/lib/swarm_sdk/validation_result.rb +0 -33
  176. data/lib/swarm_sdk/version.rb +0 -5
  177. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  178. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  179. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  180. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  181. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  182. data/lib/swarm_sdk/workflow.rb +0 -554
  183. data/lib/swarm_sdk.rb +0 -524
  184. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Builder for swarm registry in DSL
6
- #
7
- # Supports registering external swarms for composable swarms pattern.
8
- #
9
- # @example
10
- # swarms do
11
- # register "code_review", file: "./swarms/code_review.rb"
12
- # register "testing", file: "./swarms/testing.yml", keep_context: false
13
- # end
14
- #
15
- # @example Inline swarm definition
16
- # swarms do
17
- # register "tester" do
18
- # lead :tester
19
- # agent :tester do
20
- # model "gpt-4o-mini"
21
- # system "You test code"
22
- # end
23
- # end
24
- # end
25
- #
26
- class SwarmRegistryBuilder
27
- attr_reader :registrations
28
-
29
- def initialize
30
- @registrations = []
31
- end
32
-
33
- # Register a swarm from file, YAML string, or inline block
34
- #
35
- # @param name [String, Symbol] Registration name
36
- # @param file [String, nil] Path to swarm file (.rb or .yml)
37
- # @param yaml [String, nil] YAML content string
38
- # @param keep_context [Boolean] Whether to preserve conversation state (default: true)
39
- # @yield Optional block for inline swarm definition
40
- # @raise [ArgumentError] If neither file, yaml, nor block provided
41
- def register(name, file: nil, yaml: nil, keep_context: true, &block)
42
- # Validate that exactly one source is provided
43
- sources = [file, yaml, block].compact
44
- if sources.empty?
45
- raise ArgumentError, "register '#{name}' requires either file:, yaml:, or a block"
46
- elsif sources.size > 1
47
- raise ArgumentError, "register '#{name}' accepts only one of: file:, yaml:, or block (got #{sources.size})"
48
- end
49
-
50
- # Determine source type and store
51
- source = if file
52
- { type: :file, value: file }
53
- elsif yaml
54
- { type: :yaml, value: yaml }
55
- else
56
- { type: :block, value: block }
57
- end
58
-
59
- @registrations << {
60
- name: name.to_s,
61
- source: source,
62
- keep_context: keep_context,
63
- }
64
- end
65
- end
66
- end
67
- end
@@ -1,358 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Handles tool creation, registration, and permissions wrapping
6
- #
7
- # Responsibilities:
8
- # - Register explicit tools for agents
9
- # - Register default tools (Read, Grep, Glob, etc.)
10
- # - Create tool instances (with agent context)
11
- # - Wrap tools with permissions validators
12
- #
13
- # This encapsulates all tool-related logic that was previously in Swarm.
14
- class ToolConfigurator
15
- # Default tools available to all agents (unless disable_default_tools is set)
16
- DEFAULT_TOOLS = [
17
- :Read,
18
- :Grep,
19
- :Glob,
20
- ].freeze
21
-
22
- # Scratchpad tools (added if scratchpad is enabled)
23
- SCRATCHPAD_TOOLS = [
24
- :ScratchpadWrite,
25
- :ScratchpadRead,
26
- :ScratchpadList,
27
- ].freeze
28
-
29
- # Filesystem tools that can be globally disabled for security
30
- FILESYSTEM_TOOLS = [
31
- :Read,
32
- :Write,
33
- :Edit,
34
- :MultiEdit,
35
- :Grep,
36
- :Glob,
37
- :Bash,
38
- ].freeze
39
-
40
- def initialize(swarm, scratchpad_storage, plugin_storages = {})
41
- @swarm = swarm
42
- @scratchpad_storage = scratchpad_storage
43
- # Plugin storages: { plugin_name => { agent_name => storage } }
44
- # e.g., { memory: { agent1: storage1, agent2: storage2 } }
45
- @plugin_storages = plugin_storages
46
- end
47
-
48
- # Register all tools for an agent (both explicit and default)
49
- #
50
- # @param chat [AgentChat] The chat instance to register tools with
51
- # @param agent_name [Symbol] Name of the agent
52
- # @param agent_definition [AgentDefinition] Agent definition object
53
- def register_all_tools(chat:, agent_name:, agent_definition:)
54
- register_explicit_tools(chat, agent_definition.tools, agent_name: agent_name, agent_definition: agent_definition)
55
- register_default_tools(chat, agent_name: agent_name, agent_definition: agent_definition)
56
- end
57
-
58
- # Create a tool instance by name
59
- #
60
- # Uses the Registry factory pattern to instantiate tools based on their
61
- # declared requirements. This eliminates the need for a giant case statement.
62
- #
63
- # File tools and TodoWrite require agent context for tracking state.
64
- # Scratchpad tools require shared scratchpad instance.
65
- # Plugin tools are delegated to their respective plugins.
66
- #
67
- # This method is public for testing delegation from Swarm.
68
- #
69
- # @param tool_name [Symbol, String] Tool name
70
- # @param agent_name [Symbol] Agent name for context
71
- # @param directory [String] Agent's working directory
72
- # @param chat [Agent::Chat, nil] Optional chat instance for tools that need it
73
- # @param agent_definition [Agent::Definition, nil] Optional agent definition
74
- # @return [RubyLLM::Tool] Tool instance
75
- def create_tool_instance(tool_name, agent_name, directory, chat: nil, agent_definition: nil)
76
- tool_name_sym = tool_name.to_sym
77
-
78
- # Check if tool is provided by a plugin
79
- if PluginRegistry.plugin_tool?(tool_name_sym)
80
- return create_plugin_tool(tool_name_sym, agent_name, directory, chat, agent_definition)
81
- end
82
-
83
- # Use Registry factory pattern - tools declare their own requirements
84
- context = {
85
- agent_name: agent_name,
86
- directory: directory,
87
- scratchpad_storage: @scratchpad_storage,
88
- }
89
-
90
- Tools::Registry.create(tool_name_sym, context)
91
- end
92
-
93
- # Wrap a tool instance with permissions validator if configured
94
- #
95
- # This method is public for testing delegation from Swarm.
96
- #
97
- # @param tool_instance [RubyLLM::Tool] Tool instance to wrap
98
- # @param permissions_config [Hash, nil] Permission configuration
99
- # @param agent_definition [AgentDefinition] Agent definition
100
- # @return [RubyLLM::Tool] Either the wrapped tool or original tool
101
- def wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
102
- # Skip wrapping if no permissions or agent bypasses permissions
103
- return tool_instance unless permissions_config
104
- return tool_instance if agent_definition.bypass_permissions
105
-
106
- # Create permissions config and wrap tool with validator
107
- permissions = Permissions::Config.new(
108
- permissions_config,
109
- base_directory: agent_definition.directory,
110
- )
111
-
112
- Permissions::Validator.new(tool_instance, permissions)
113
- end
114
-
115
- private
116
-
117
- # Register explicitly configured tools
118
- #
119
- # @param chat [AgentChat] The chat instance
120
- # @param tool_configs [Array<Hash>] Tool configurations with optional permissions
121
- # @param agent_name [Symbol] Agent name
122
- # @param agent_definition [AgentDefinition] Agent definition
123
- def register_explicit_tools(chat, tool_configs, agent_name:, agent_definition:)
124
- # Validate filesystem tools if globally disabled
125
- unless @swarm.allow_filesystem_tools
126
- # Extract tool names from hashes and convert to symbols for comparison
127
- forbidden = tool_configs.map { |tc| tc[:name].to_sym }.select { |name| FILESYSTEM_TOOLS.include?(name) }
128
- unless forbidden.empty?
129
- raise ConfigurationError,
130
- "Filesystem tools are globally disabled (SwarmSDK.settings.allow_filesystem_tools = false) " \
131
- "but agent '#{agent_name}' attempts to use: #{forbidden.join(", ")}.\n\n" \
132
- "This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
133
- "To use filesystem tools, set SwarmSDK.settings.allow_filesystem_tools = true before loading the swarm."
134
- end
135
- end
136
-
137
- tool_configs.each do |tool_config|
138
- tool_name = tool_config[:name]
139
- permissions_config = tool_config[:permissions]
140
-
141
- # Create tool instance
142
- tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
143
-
144
- # Wrap with permissions and add to chat
145
- wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
146
- end
147
- end
148
-
149
- # Register default tools for agents (unless disabled)
150
- #
151
- # Note: Memory tools are registered separately and are NOT affected by
152
- # disable_default_tools, since they're configured via memory {} block.
153
- #
154
- # @param chat [AgentChat] The chat instance
155
- # @param agent_name [Symbol] Agent name
156
- # @param agent_definition [AgentDefinition] Agent definition
157
- def register_default_tools(chat, agent_name:, agent_definition:)
158
- # Get explicit tool names to avoid duplicates
159
- explicit_tool_names = agent_definition.tools.map { |t| t[:name] }.to_set
160
-
161
- # Register core default tools (unless disabled)
162
- if agent_definition.disable_default_tools != true
163
- DEFAULT_TOOLS.each do |tool_name|
164
- # Skip filesystem tools if globally disabled
165
- next if !@swarm.allow_filesystem_tools && FILESYSTEM_TOOLS.include?(tool_name)
166
-
167
- register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
168
- end
169
-
170
- # Register scratchpad tools if enabled
171
- if @swarm.scratchpad_enabled?
172
- SCRATCHPAD_TOOLS.each do |tool_name|
173
- register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
174
- end
175
- end
176
- end
177
-
178
- # Register plugin tools if plugin storage is enabled for this agent
179
- # Plugin tools ARE affected by disable_default_tools (allows fine-grained control)
180
- register_plugin_tools(chat, agent_name, agent_definition, explicit_tool_names)
181
- end
182
-
183
- # Register a tool if not already explicit or disabled
184
- def register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
185
- # Skip if already registered explicitly
186
- return if explicit_tool_names.include?(tool_name)
187
-
188
- # Skip if tool is in the disable list
189
- return if tool_disabled?(tool_name, agent_definition.disable_default_tools)
190
-
191
- tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
192
- permissions_config = resolve_default_permissions(tool_name, agent_definition)
193
-
194
- wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
195
- end
196
-
197
- # Wrap tool with permissions and add to chat
198
- #
199
- # This is the common pattern for registering tools:
200
- # 1. Wrap with permissions validator (if configured)
201
- # 2. Add to chat
202
- #
203
- # @param chat [Agent::Chat] The chat instance
204
- # @param tool_instance [RubyLLM::Tool] Tool instance
205
- # @param permissions_config [Hash, nil] Permissions configuration
206
- # @param agent_definition [Agent::Definition] Agent definition
207
- # @return [void]
208
- def wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
209
- tool_instance = wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
210
- chat.add_tool(tool_instance)
211
- end
212
-
213
- # Resolve permissions for a default/plugin tool
214
- #
215
- # Looks up permissions in agent-specific config first, falls back to global defaults.
216
- #
217
- # @param tool_name [Symbol] Tool name
218
- # @param agent_definition [Agent::Definition] Agent definition
219
- # @return [Hash, nil] Permissions configuration or nil
220
- def resolve_default_permissions(tool_name, agent_definition)
221
- agent_definition.agent_permissions[tool_name] || agent_definition.default_permissions[tool_name]
222
- end
223
-
224
- # Create a tool instance via plugin
225
- #
226
- # @param tool_name [Symbol] Tool name
227
- # @param agent_name [Symbol] Agent name
228
- # @param directory [String] Working directory
229
- # @param chat [Agent::Chat, nil] Chat instance
230
- # @param agent_definition [Agent::Definition, nil] Agent definition
231
- # @return [RubyLLM::Tool] Tool instance
232
- def create_plugin_tool(tool_name, agent_name, directory, chat, agent_definition)
233
- plugin = PluginRegistry.plugin_for_tool(tool_name)
234
- raise ConfigurationError, "Tool #{tool_name} is not provided by any plugin" unless plugin
235
-
236
- # V7.0: Extract base name for storage lookup (handles delegation instances)
237
- # For primary agents: :tester → :tester (no change)
238
- # For delegation instances: "tester@frontend" → :tester (extracts base)
239
- base_name = agent_name.to_s.split("@").first.to_sym
240
-
241
- # Get plugin storage using BASE NAME (shared across instances)
242
- plugin_storages = @plugin_storages[plugin.name] || {}
243
- storage = plugin_storages[base_name] # ← Changed from agent_name to base_name
244
-
245
- # Build context for tool creation
246
- # Pass full agent_name for tool state tracking (TodoWrite, ReadTracker, etc.)
247
- context = {
248
- agent_name: agent_name, # Full instance name for tool's use
249
- directory: directory,
250
- storage: storage, # Shared storage by base name
251
- agent_definition: agent_definition,
252
- chat: chat,
253
- tool_configurator: self,
254
- }
255
-
256
- plugin.create_tool(tool_name, context)
257
- end
258
-
259
- # Register plugin-provided tools for an agent
260
- #
261
- # Asks all plugins if they have tools to register for this agent.
262
- #
263
- # @param chat [Agent::Chat] Chat instance
264
- # @param agent_name [Symbol] Agent name
265
- # @param agent_definition [Agent::Definition] Agent definition
266
- # @param explicit_tool_names [Set<Symbol>] Already-registered tool names
267
- def register_plugin_tools(chat, agent_name, agent_definition, explicit_tool_names)
268
- PluginRegistry.all.each do |plugin|
269
- # Check if plugin has storage enabled for this agent
270
- next unless plugin.storage_enabled?(agent_definition)
271
-
272
- # Register each tool provided by the plugin
273
- plugin.tools.each do |tool_name|
274
- # Skip if already registered explicitly
275
- next if explicit_tool_names.include?(tool_name)
276
-
277
- # Skip if tool is disabled via disable_default_tools
278
- next if tool_disabled?(tool_name, agent_definition.disable_default_tools)
279
-
280
- tool_instance = create_tool_instance(
281
- tool_name,
282
- agent_name,
283
- agent_definition.directory,
284
- chat: chat,
285
- agent_definition: agent_definition,
286
- )
287
-
288
- permissions_config = resolve_default_permissions(tool_name, agent_definition)
289
-
290
- wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
291
- end
292
- end
293
- end
294
-
295
- # Check if a tool should be disabled based on disable_default_tools config
296
- #
297
- # @param tool_name [Symbol] Tool name to check
298
- # @param disable_config [nil, Boolean, Symbol, Array<Symbol>] Disable configuration
299
- # @return [Boolean] True if tool should be disabled
300
- def tool_disabled?(tool_name, disable_config)
301
- return false if disable_config.nil?
302
-
303
- # Normalize tool_name to symbol for comparison
304
- tool_name_sym = tool_name.to_sym
305
-
306
- if disable_config == true
307
- # Disable all default tools
308
- true
309
- elsif disable_config.is_a?(Symbol)
310
- # Single tool name
311
- disable_config == tool_name_sym
312
- elsif disable_config.is_a?(String)
313
- # Single tool name as string (from YAML)
314
- disable_config.to_sym == tool_name_sym
315
- elsif disable_config.is_a?(Array)
316
- # Disable only tools in the array - normalize to symbols for comparison
317
- disable_config.map(&:to_sym).include?(tool_name_sym)
318
- else
319
- false
320
- end
321
- end
322
-
323
- # Register agent delegation tools
324
- #
325
- # Creates delegation tools that allow one agent to call another.
326
- #
327
- # @param chat [AgentChat] The chat instance
328
- # @param delegate_names [Array<Symbol>] Names of agents to delegate to
329
- # @param agent_name [Symbol] Name of the agent doing the delegating
330
- def register_delegation_tools(chat, delegate_names, agent_name:)
331
- return if delegate_names.empty?
332
-
333
- delegate_names.each do |delegate_name|
334
- delegate_name = delegate_name.to_sym
335
-
336
- unless @agents.key?(delegate_name)
337
- raise ConfigurationError, "Agent delegates to unknown agent '#{delegate_name}'"
338
- end
339
-
340
- # Create a tool that delegates to the specified agent
341
- delegate_agent = @agents[delegate_name]
342
- delegate_definition = @agent_definitions[delegate_name]
343
-
344
- tool = Tools::Delegate.new(
345
- delegate_name: delegate_name.to_s,
346
- delegate_description: delegate_definition.description,
347
- delegate_chat: delegate_agent,
348
- agent_name: agent_name,
349
- swarm: @swarm,
350
- delegating_chat: chat,
351
- )
352
-
353
- chat.add_tool(tool)
354
- end
355
- end
356
- end
357
- end
358
- end