swarm_sdk 2.7.14 → 3.0.0.alpha2

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +16 -0
  3. data/lib/swarm_sdk/ruby_llm_patches/init.rb +4 -1
  4. data/lib/swarm_sdk/v3/agent.rb +1165 -0
  5. data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
  6. data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
  7. data/lib/swarm_sdk/v3/configuration.rb +490 -0
  8. data/lib/swarm_sdk/v3/debug_log.rb +86 -0
  9. data/lib/swarm_sdk/v3/event_stream.rb +130 -0
  10. data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
  11. data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
  12. data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
  13. data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
  14. data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
  15. data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
  16. data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
  17. data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
  18. data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
  19. data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
  20. data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
  21. data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
  22. data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
  23. data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
  24. data/lib/swarm_sdk/v3/memory/card.rb +206 -0
  25. data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
  26. data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
  27. data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
  28. data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
  29. data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
  30. data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
  31. data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
  32. data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
  33. data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
  34. data/lib/swarm_sdk/v3/memory/store.rb +489 -0
  35. data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
  36. data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
  37. data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
  38. data/lib/swarm_sdk/v3/tools/base.rb +80 -0
  39. data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
  40. data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
  41. data/lib/swarm_sdk/v3/tools/document_converters/base.rb +84 -0
  42. data/lib/swarm_sdk/v3/tools/document_converters/docx_converter.rb +120 -0
  43. data/lib/swarm_sdk/v3/tools/document_converters/pdf_converter.rb +111 -0
  44. data/lib/swarm_sdk/v3/tools/document_converters/xlsx_converter.rb +128 -0
  45. data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
  46. data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
  47. data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
  48. data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
  49. data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
  50. data/lib/swarm_sdk/v3/tools/read.rb +213 -0
  51. data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
  52. data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
  53. data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
  54. data/lib/swarm_sdk/v3/tools/think.rb +88 -0
  55. data/lib/swarm_sdk/v3/tools/write.rb +87 -0
  56. data/lib/swarm_sdk/v3.rb +145 -0
  57. metadata +88 -149
  58. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
  59. data/lib/swarm_sdk/agent/builder.rb +0 -705
  60. data/lib/swarm_sdk/agent/chat.rb +0 -1438
  61. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
  62. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  63. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  64. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -85
  65. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
  66. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  67. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  68. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -134
  69. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  70. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
  71. data/lib/swarm_sdk/agent/context.rb +0 -115
  72. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  73. data/lib/swarm_sdk/agent/definition.rb +0 -588
  74. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
  75. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -173
  76. data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
  77. data/lib/swarm_sdk/agent_registry.rb +0 -146
  78. data/lib/swarm_sdk/builders/base_builder.rb +0 -558
  79. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  80. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -42
  81. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  82. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  83. data/lib/swarm_sdk/config.rb +0 -368
  84. data/lib/swarm_sdk/configuration/parser.rb +0 -397
  85. data/lib/swarm_sdk/configuration/translator.rb +0 -285
  86. data/lib/swarm_sdk/configuration.rb +0 -165
  87. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  88. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
  89. data/lib/swarm_sdk/context_compactor.rb +0 -335
  90. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  91. data/lib/swarm_sdk/context_management/context.rb +0 -328
  92. data/lib/swarm_sdk/custom_tool_registry.rb +0 -226
  93. data/lib/swarm_sdk/defaults.rb +0 -251
  94. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  95. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  96. data/lib/swarm_sdk/hooks/context.rb +0 -197
  97. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  98. data/lib/swarm_sdk/hooks/error.rb +0 -29
  99. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  100. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  101. data/lib/swarm_sdk/hooks/result.rb +0 -150
  102. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -256
  103. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  104. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  105. data/lib/swarm_sdk/log_collector.rb +0 -227
  106. data/lib/swarm_sdk/log_stream.rb +0 -127
  107. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  108. data/lib/swarm_sdk/model_aliases.json +0 -8
  109. data/lib/swarm_sdk/models.json +0 -44002
  110. data/lib/swarm_sdk/models.rb +0 -161
  111. data/lib/swarm_sdk/node_context.rb +0 -245
  112. data/lib/swarm_sdk/observer/builder.rb +0 -81
  113. data/lib/swarm_sdk/observer/config.rb +0 -45
  114. data/lib/swarm_sdk/observer/manager.rb +0 -248
  115. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  116. data/lib/swarm_sdk/permissions/config.rb +0 -239
  117. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  118. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  119. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  120. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  121. data/lib/swarm_sdk/plugin.rb +0 -309
  122. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  123. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  124. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -119
  125. data/lib/swarm_sdk/restore_result.rb +0 -65
  126. data/lib/swarm_sdk/result.rb +0 -241
  127. data/lib/swarm_sdk/snapshot.rb +0 -156
  128. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  129. data/lib/swarm_sdk/state_restorer.rb +0 -476
  130. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  131. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -648
  132. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -204
  133. data/lib/swarm_sdk/swarm/builder.rb +0 -256
  134. data/lib/swarm_sdk/swarm/executor.rb +0 -446
  135. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -162
  136. data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -361
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -290
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
  141. data/lib/swarm_sdk/swarm.rb +0 -973
  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/base.rb +0 -63
  145. data/lib/swarm_sdk/tools/bash.rb +0 -280
  146. data/lib/swarm_sdk/tools/clock.rb +0 -46
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -389
  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 -167
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
  160. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  161. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  162. data/lib/swarm_sdk/tools/read.rb +0 -261
  163. data/lib/swarm_sdk/tools/registry.rb +0 -205
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  166. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  167. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  168. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -273
  169. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  170. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  171. data/lib/swarm_sdk/tools/think.rb +0 -100
  172. data/lib/swarm_sdk/tools/todo_write.rb +0 -237
  173. data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
  174. data/lib/swarm_sdk/tools/write.rb +0 -112
  175. data/lib/swarm_sdk/transcript_builder.rb +0 -278
  176. data/lib/swarm_sdk/utils.rb +0 -68
  177. data/lib/swarm_sdk/validation_result.rb +0 -33
  178. data/lib/swarm_sdk/version.rb +0 -5
  179. data/lib/swarm_sdk/workflow/agent_config.rb +0 -95
  180. data/lib/swarm_sdk/workflow/builder.rb +0 -227
  181. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  182. data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
  183. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
  184. data/lib/swarm_sdk/workflow.rb +0 -589
  185. data/lib/swarm_sdk.rb +0 -721
@@ -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,392 +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
- # Tool lookup order:
64
- # 1. Plugin tools (registered via SwarmSDK::PluginRegistry)
65
- # 2. Custom tools (registered via SwarmSDK.register_tool)
66
- # 3. Built-in tools (SwarmSDK::Tools::Registry)
67
- #
68
- # File tools and TodoWrite require agent context for tracking state.
69
- # Scratchpad tools require shared scratchpad instance.
70
- # Plugin tools are delegated to their respective plugins.
71
- #
72
- # This method is public for testing delegation from Swarm.
73
- #
74
- # @param tool_name [Symbol, String] Tool name
75
- # @param agent_name [Symbol] Agent name for context
76
- # @param directory [String] Agent's working directory
77
- # @param chat [Agent::Chat, nil] Optional chat instance for tools that need it
78
- # @param agent_definition [Agent::Definition, nil] Optional agent definition
79
- # @return [RubyLLM::Tool] Tool instance
80
- def create_tool_instance(tool_name, agent_name, directory, chat: nil, agent_definition: nil)
81
- tool_name_sym = tool_name.to_sym
82
-
83
- # Check if tool is provided by a plugin
84
- if PluginRegistry.plugin_tool?(tool_name_sym)
85
- return create_plugin_tool(tool_name_sym, agent_name, directory, chat, agent_definition)
86
- end
87
-
88
- # Check if tool is a custom registered tool
89
- if CustomToolRegistry.registered?(tool_name_sym)
90
- context = {
91
- agent_name: agent_name,
92
- directory: directory,
93
- }
94
- return CustomToolRegistry.create(tool_name_sym, context)
95
- end
96
-
97
- # Use Registry factory pattern for built-in tools
98
- context = {
99
- agent_name: agent_name,
100
- directory: directory,
101
- scratchpad_storage: @scratchpad_storage,
102
- }
103
-
104
- Tools::Registry.create(tool_name_sym, context)
105
- end
106
-
107
- # Wrap a tool instance with permissions validator if configured
108
- #
109
- # This method is public for testing delegation from Swarm.
110
- #
111
- # @param tool_instance [RubyLLM::Tool] Tool instance to wrap
112
- # @param permissions_config [Hash, nil] Permission configuration
113
- # @param agent_definition [AgentDefinition] Agent definition
114
- # @return [RubyLLM::Tool] Either the wrapped tool or original tool
115
- def wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
116
- # Skip wrapping if no permissions or agent bypasses permissions
117
- return tool_instance unless permissions_config
118
- return tool_instance if agent_definition.bypass_permissions
119
-
120
- # Create permissions config and wrap tool with validator
121
- permissions = Permissions::Config.new(
122
- permissions_config,
123
- base_directory: agent_definition.directory,
124
- )
125
-
126
- Permissions::Validator.new(tool_instance, permissions)
127
- end
128
-
129
- private
130
-
131
- # Register explicitly configured tools
132
- #
133
- # @param chat [AgentChat] The chat instance
134
- # @param tool_configs [Array<Hash>] Tool configurations with optional permissions
135
- # @param agent_name [Symbol] Agent name
136
- # @param agent_definition [AgentDefinition] Agent definition
137
- def register_explicit_tools(chat, tool_configs, agent_name:, agent_definition:)
138
- # Validate filesystem tools if globally disabled
139
- unless @swarm.allow_filesystem_tools
140
- # Extract tool names from hashes and convert to symbols for comparison
141
- forbidden = tool_configs.map { |tc| tc[:name].to_sym }.select { |name| FILESYSTEM_TOOLS.include?(name) }
142
- unless forbidden.empty?
143
- raise ConfigurationError,
144
- "Filesystem tools are globally disabled (SwarmSDK.config.allow_filesystem_tools = false) " \
145
- "but agent '#{agent_name}' attempts to use: #{forbidden.join(", ")}.\n\n" \
146
- "This is a system-wide security setting that cannot be overridden by swarm configuration.\n" \
147
- "To use filesystem tools, set SwarmSDK.config.allow_filesystem_tools = true before loading the swarm."
148
- end
149
- end
150
-
151
- tool_configs.each do |tool_config|
152
- tool_name = tool_config[:name]
153
- permissions_config = tool_config[:permissions]
154
-
155
- # Create tool instance
156
- tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
157
-
158
- # Wrap with permissions and add to chat
159
- wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
160
- end
161
- end
162
-
163
- # Register default tools for agents (unless disabled)
164
- #
165
- # Note: Memory tools are registered separately and are NOT affected by
166
- # disable_default_tools, since they're configured via memory {} block.
167
- #
168
- # @param chat [AgentChat] The chat instance
169
- # @param agent_name [Symbol] Agent name
170
- # @param agent_definition [AgentDefinition] Agent definition
171
- def register_default_tools(chat, agent_name:, agent_definition:)
172
- # Get explicit tool names to avoid duplicates
173
- explicit_tool_names = agent_definition.tools.map { |t| t[:name] }.to_set
174
-
175
- # Register core default tools (unless disabled)
176
- if agent_definition.disable_default_tools != true
177
- DEFAULT_TOOLS.each do |tool_name|
178
- # Skip filesystem tools if globally disabled
179
- next if !@swarm.allow_filesystem_tools && FILESYSTEM_TOOLS.include?(tool_name)
180
-
181
- register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
182
- end
183
-
184
- # Register scratchpad tools if enabled
185
- if @swarm.scratchpad_enabled?
186
- SCRATCHPAD_TOOLS.each do |tool_name|
187
- register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
188
- end
189
- end
190
- end
191
-
192
- # Register plugin tools if plugin storage is enabled for this agent
193
- # Plugin tools ARE affected by disable_default_tools (allows fine-grained control)
194
- register_plugin_tools(chat, agent_name, agent_definition, explicit_tool_names)
195
- end
196
-
197
- # Register a tool if not already explicit or disabled
198
- def register_tool_if_not_disabled(chat, tool_name, explicit_tool_names, agent_name, agent_definition)
199
- # Skip if already registered explicitly
200
- return if explicit_tool_names.include?(tool_name)
201
-
202
- # Skip if tool is in the disable list
203
- return if tool_disabled?(tool_name, agent_definition.disable_default_tools)
204
-
205
- tool_instance = create_tool_instance(tool_name, agent_name, agent_definition.directory)
206
- permissions_config = resolve_default_permissions(tool_name, agent_definition)
207
-
208
- wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition)
209
- end
210
-
211
- # Wrap tool with permissions and add to chat
212
- #
213
- # This is the common pattern for registering tools:
214
- # 1. Wrap with permissions validator (if configured)
215
- # 2. Add to chat
216
- #
217
- # @param chat [Agent::Chat] The chat instance
218
- # @param tool_instance [RubyLLM::Tool] Tool instance
219
- # @param permissions_config [Hash, nil] Permissions configuration
220
- # @param agent_definition [Agent::Definition] Agent definition
221
- # @return [void]
222
- def wrap_and_add_tool(chat, tool_instance, permissions_config, agent_definition, source: :builtin, metadata: {})
223
- base_tool = tool_instance # Keep reference to unwrapped tool
224
- wrapped_tool = wrap_tool_with_permissions(tool_instance, permissions_config, agent_definition)
225
-
226
- # Register in tool registry (Plan 025)
227
- chat.tool_registry.register(
228
- wrapped_tool,
229
- base_tool: base_tool,
230
- source: source,
231
- metadata: metadata.merge(permissions: permissions_config),
232
- )
233
- end
234
-
235
- # Resolve permissions for a default/plugin tool
236
- #
237
- # Looks up permissions in agent-specific config first, falls back to global defaults.
238
- #
239
- # @param tool_name [Symbol] Tool name
240
- # @param agent_definition [Agent::Definition] Agent definition
241
- # @return [Hash, nil] Permissions configuration or nil
242
- def resolve_default_permissions(tool_name, agent_definition)
243
- agent_definition.agent_permissions[tool_name] || agent_definition.default_permissions[tool_name]
244
- end
245
-
246
- # Create a tool instance via plugin
247
- #
248
- # @param tool_name [Symbol] Tool name
249
- # @param agent_name [Symbol] Agent name
250
- # @param directory [String] Working directory
251
- # @param chat [Agent::Chat, nil] Chat instance
252
- # @param agent_definition [Agent::Definition, nil] Agent definition
253
- # @return [RubyLLM::Tool] Tool instance
254
- def create_plugin_tool(tool_name, agent_name, directory, chat, agent_definition)
255
- plugin = PluginRegistry.plugin_for_tool(tool_name)
256
- raise ConfigurationError, "Tool #{tool_name} is not provided by any plugin" unless plugin
257
-
258
- # V7.0: Extract base name for storage lookup (handles delegation instances)
259
- # For primary agents: :tester → :tester (no change)
260
- # For delegation instances: "tester@frontend" → :tester (extracts base)
261
- base_name = agent_name.to_s.split("@").first.to_sym
262
-
263
- # Get plugin storage using BASE NAME (shared across instances)
264
- plugin_storages = @plugin_storages[plugin.name] || {}
265
- storage = plugin_storages[base_name] # ← Changed from agent_name to base_name
266
-
267
- # Build context for tool creation
268
- # Pass full agent_name for tool state tracking (TodoWrite, ReadTracker, etc.)
269
- context = {
270
- agent_name: agent_name, # Full instance name for tool's use
271
- directory: directory,
272
- storage: storage, # Shared storage by base name
273
- agent_definition: agent_definition,
274
- chat: chat,
275
- tool_configurator: self,
276
- }
277
-
278
- plugin.create_tool(tool_name, context)
279
- end
280
-
281
- # Register plugin-provided tools for an agent
282
- #
283
- # Asks all plugins if they have tools to register for this agent.
284
- #
285
- # @param chat [Agent::Chat] Chat instance
286
- # @param agent_name [Symbol] Agent name
287
- # @param agent_definition [Agent::Definition] Agent definition
288
- # @param explicit_tool_names [Set<Symbol>] Already-registered tool names
289
- def register_plugin_tools(chat, agent_name, agent_definition, explicit_tool_names)
290
- PluginRegistry.all.each do |plugin|
291
- # Check if plugin has storage enabled for this agent
292
- next unless plugin.memory_configured?(agent_definition)
293
-
294
- # Register each tool provided by the plugin
295
- plugin.tools.each do |tool_name|
296
- # Skip if already registered explicitly
297
- next if explicit_tool_names.include?(tool_name)
298
-
299
- # Skip if tool is disabled via disable_default_tools
300
- next if tool_disabled?(tool_name, agent_definition.disable_default_tools)
301
-
302
- tool_instance = create_tool_instance(
303
- tool_name,
304
- agent_name,
305
- agent_definition.directory,
306
- chat: chat,
307
- agent_definition: agent_definition,
308
- )
309
-
310
- permissions_config = resolve_default_permissions(tool_name, agent_definition)
311
-
312
- wrap_and_add_tool(
313
- chat,
314
- tool_instance,
315
- permissions_config,
316
- agent_definition,
317
- source: :plugin,
318
- metadata: { plugin_name: plugin.class.name },
319
- )
320
- end
321
- end
322
- end
323
-
324
- # Check if a tool should be disabled based on disable_default_tools config
325
- #
326
- # @param tool_name [Symbol] Tool name to check
327
- # @param disable_config [nil, Boolean, Symbol, Array<Symbol>] Disable configuration
328
- # @return [Boolean] True if tool should be disabled
329
- def tool_disabled?(tool_name, disable_config)
330
- return false if disable_config.nil?
331
-
332
- # Normalize tool_name to symbol for comparison
333
- tool_name_sym = tool_name.to_sym
334
-
335
- if disable_config == true
336
- # Disable all default tools
337
- true
338
- elsif disable_config.is_a?(Symbol)
339
- # Single tool name
340
- disable_config == tool_name_sym
341
- elsif disable_config.is_a?(String)
342
- # Single tool name as string (from YAML)
343
- disable_config.to_sym == tool_name_sym
344
- elsif disable_config.is_a?(Array)
345
- # Disable only tools in the array - normalize to symbols for comparison
346
- disable_config.map(&:to_sym).include?(tool_name_sym)
347
- else
348
- false
349
- end
350
- end
351
-
352
- # Register agent delegation tools
353
- #
354
- # Creates delegation tools that allow one agent to call another.
355
- #
356
- # @param chat [AgentChat] The chat instance
357
- # @param delegate_names [Array<Symbol>] Names of agents to delegate to
358
- # @param agent_name [Symbol] Name of the agent doing the delegating
359
- def register_delegation_tools(chat, delegate_names, agent_name:)
360
- return if delegate_names.empty?
361
-
362
- delegate_names.each do |delegate_name|
363
- delegate_name = delegate_name.to_sym
364
-
365
- unless @agents.key?(delegate_name)
366
- raise ConfigurationError, "Agent delegates to unknown agent '#{delegate_name}'"
367
- end
368
-
369
- # Create a tool that delegates to the specified agent
370
- delegate_agent = @agents[delegate_name]
371
- delegate_definition = @agent_definitions[delegate_name]
372
-
373
- tool = Tools::Delegate.new(
374
- delegate_name: delegate_name.to_s,
375
- delegate_description: delegate_definition.description,
376
- delegate_chat: delegate_agent,
377
- agent_name: agent_name,
378
- swarm: @swarm,
379
- delegating_chat: chat,
380
- )
381
-
382
- # Register in tool registry (Plan 025)
383
- chat.tool_registry.register(
384
- tool,
385
- source: :delegation,
386
- metadata: { delegate_name: delegate_name },
387
- )
388
- end
389
- end
390
- end
391
- end
392
- end