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,204 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # AllAgentsBuilder for configuring settings that apply to all agents
6
- #
7
- # Settings configured here are applied to ALL agents, but can be overridden
8
- # at the agent level. This is useful for shared configuration like:
9
- # - Common provider/base_url (all agents use same proxy)
10
- # - Shared timeout settings
11
- # - Global permissions
12
- #
13
- # @example
14
- # all_agents do
15
- # provider :openai
16
- # base_url "http://proxy.com/v1"
17
- # timeout 180
18
- # tools :Read, :Write
19
- # coding_agent false
20
- # end
21
- class AllAgentsBuilder
22
- attr_reader :hooks, :permissions_config, :tools_list
23
-
24
- def initialize
25
- @tools_list = []
26
- @hooks = []
27
- @permissions_config = {}
28
- @model = nil
29
- @provider = nil
30
- @base_url = nil
31
- @api_version = nil
32
- @request_timeout = nil
33
- @turn_timeout = nil
34
- @parameters = nil
35
- @headers = nil
36
- @coding_agent = nil
37
- @disable_default_tools = nil
38
- @streaming = nil
39
- @thinking = nil
40
- @disable_environment_info = nil
41
- end
42
-
43
- # Set model for all agents
44
- def model(model_name)
45
- @model = model_name
46
- end
47
-
48
- # Set provider for all agents
49
- def provider(provider_name)
50
- @provider = provider_name
51
- end
52
-
53
- # Set base URL for all agents
54
- def base_url(url)
55
- @base_url = url
56
- end
57
-
58
- # Set API version for all agents
59
- def api_version(version)
60
- @api_version = version
61
- end
62
-
63
- # Set request timeout for all agents
64
- def request_timeout(seconds)
65
- @request_timeout = seconds
66
- end
67
-
68
- # Set turn timeout for all agents
69
- def turn_timeout(seconds)
70
- @turn_timeout = seconds
71
- end
72
-
73
- # Set parameters for all agents
74
- def parameters(params)
75
- @parameters = params
76
- end
77
-
78
- # Set headers for all agents
79
- def headers(header_hash)
80
- @headers = header_hash
81
- end
82
-
83
- # Set coding_agent flag for all agents
84
- def coding_agent(enabled)
85
- @coding_agent = enabled
86
- end
87
-
88
- # Disable default tools for all agents
89
- #
90
- # @param value [Boolean, Array<Symbol>]
91
- # - true: Disable ALL default tools
92
- # - Array of symbols: Disable specific tools (e.g., [:Think, :TodoWrite])
93
- def disable_default_tools(value)
94
- @disable_default_tools = value
95
- end
96
-
97
- # Enable or disable streaming for all agents
98
- #
99
- # @param value [Boolean] If true, enables streaming; if false, disables it
100
- def streaming(value)
101
- @streaming = value
102
- end
103
-
104
- # Disable environment info for all agents
105
- #
106
- # @param enabled [Boolean] Whether to disable environment info in system prompts
107
- def disable_environment_info(enabled)
108
- @disable_environment_info = enabled
109
- end
110
-
111
- # Configure extended thinking for all agents
112
- #
113
- # @param effort [Symbol, String, nil] Reasoning effort (:low, :medium, :high) — OpenAI
114
- # @param budget [Integer, nil] Token budget for thinking — Anthropic
115
- def thinking(effort: nil, budget: nil)
116
- raise ArgumentError, "thinking requires :effort or :budget" if effort.nil? && budget.nil?
117
-
118
- @thinking = { effort: effort, budget: budget }.compact
119
- end
120
-
121
- # Add tools that all agents will have
122
- def tools(*tool_names)
123
- @tools_list.concat(tool_names)
124
- end
125
-
126
- # Add hook for all agents (agent-level events only)
127
- #
128
- # @example
129
- # hook :pre_tool_use, matcher: "Write" do |ctx|
130
- # # Applies to all agents
131
- # end
132
- def hook(event, matcher: nil, command: nil, timeout: nil, &block)
133
- # Validate agent-level events
134
- agent_events = [
135
- :pre_tool_use,
136
- :post_tool_use,
137
- :user_prompt,
138
- :agent_step,
139
- :agent_stop,
140
- :first_message,
141
- :pre_delegation,
142
- :post_delegation,
143
- :context_warning,
144
- ]
145
-
146
- unless agent_events.include?(event)
147
- raise ArgumentError, "Invalid all_agents hook: #{event}. Swarm-level events (:swarm_start, :swarm_stop) cannot be used in all_agents block."
148
- end
149
-
150
- @hooks << { event: event, matcher: matcher, command: command, timeout: timeout, block: block }
151
- end
152
-
153
- # Configure permissions for all agents
154
- #
155
- # Supports two forms:
156
- # 1. Block form (DSL): permissions do ... end
157
- # 2. Direct hash (internal/YAML): set_permissions_hash(hash)
158
- #
159
- # @example Block form
160
- # permissions do
161
- # Write.allow_paths "tmp/**/*"
162
- # Write.deny_paths "tmp/secrets/**"
163
- # Bash.allow_commands "^git status$"
164
- # end
165
- def permissions(&block)
166
- @permissions_config = PermissionsBuilder.build(&block)
167
- end
168
-
169
- # Set permissions directly from hash (for YAML translation)
170
- #
171
- # This is intentionally separate from permissions() to keep the DSL clean.
172
- # Called by Configuration when translating YAML permissions.
173
- #
174
- # @param hash [Hash] Permissions configuration hash
175
- # @return [void]
176
- def permissions_hash=(hash)
177
- @permissions_config = hash || {}
178
- end
179
-
180
- # Convert to hash for merging with agent configs
181
- #
182
- # @return [Hash] Configuration hash
183
- def to_h
184
- {
185
- model: @model,
186
- provider: @provider,
187
- base_url: @base_url,
188
- api_version: @api_version,
189
- request_timeout: @request_timeout,
190
- turn_timeout: @turn_timeout,
191
- parameters: @parameters,
192
- headers: @headers,
193
- coding_agent: @coding_agent,
194
- disable_default_tools: @disable_default_tools,
195
- streaming: @streaming,
196
- thinking: @thinking,
197
- disable_environment_info: @disable_environment_info,
198
- tools: @tools_list,
199
- permissions: @permissions_config,
200
- }.compact
201
- end
202
- end
203
- end
204
- end
@@ -1,256 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class Swarm
5
- # Builder provides a beautiful Ruby DSL for building swarms
6
- #
7
- # The DSL combines YAML simplicity with Ruby power, enabling:
8
- # - Fluent, chainable configuration
9
- # - Hooks as Ruby blocks OR shell commands
10
- # - Full Ruby language features (variables, conditionals, loops)
11
- # - Type-safe, IDE-friendly API
12
- #
13
- # @example Basic usage
14
- # swarm = SwarmSDK.build do
15
- # name "Dev Team"
16
- # lead :backend
17
- #
18
- # agent :backend do
19
- # model "gpt-5"
20
- # prompt "You build APIs"
21
- # tools :Read, :Write, :Bash
22
- #
23
- # # Hook as Ruby block - inline logic!
24
- # hook :pre_tool_use, matcher: "Bash" do |ctx|
25
- # SwarmSDK::Hooks::Result.halt("Blocked!") if ctx.tool_call.parameters[:command].include?("rm -rf")
26
- # end
27
- # end
28
- # end
29
- #
30
- # swarm.execute("Build auth API")
31
- class Builder < Builders::BaseBuilder
32
- # Main entry point for DSL
33
- #
34
- # @example
35
- # swarm = SwarmSDK.build do
36
- # name "Team"
37
- # agent :backend { ... }
38
- # end
39
- class << self
40
- def build(allow_filesystem_tools: nil, &block)
41
- builder = new(allow_filesystem_tools: allow_filesystem_tools)
42
- builder.instance_eval(&block)
43
- builder.build_swarm
44
- end
45
- end
46
-
47
- def initialize(allow_filesystem_tools: nil)
48
- super
49
- @lead_agent = nil
50
- @swarm_hooks = []
51
- @observer_configs = []
52
- @execution_timeout = nil
53
- end
54
-
55
- # Set execution timeout (seconds)
56
- def execution_timeout(seconds)
57
- @execution_timeout = seconds
58
- end
59
-
60
- # Set lead agent
61
- def lead(agent_name)
62
- @lead_agent = agent_name
63
- end
64
-
65
- # Define observer agent behavior
66
- #
67
- # Configures an agent to run in parallel with main execution,
68
- # triggered by specific events. The block defines event handlers.
69
- #
70
- # @param agent_name [Symbol] Name of agent to use as observer (must be defined)
71
- # @param options [Hash] Optional observer settings (timeout, max_concurrent, etc.)
72
- # @yield Observer configuration block
73
- #
74
- # @example Basic observer
75
- # observer :profiler do
76
- # on :swarm_start do |event|
77
- # "Analyze this prompt: #{event[:prompt]}"
78
- # end
79
- # end
80
- #
81
- # @example Observer with options
82
- # observer :monitor, timeout: 120 do
83
- # on :tool_call do |event|
84
- # next unless event[:tool_name] == "Bash"
85
- # "Check command: #{event[:arguments][:command]}"
86
- # end
87
- # end
88
- def observer(agent_name, **options, &block)
89
- unless @agents.key?(agent_name)
90
- raise ConfigurationError,
91
- "Observer agent '#{agent_name}' not defined. " \
92
- "Define the agent first with `agent :#{agent_name} do ... end`"
93
- end
94
-
95
- config = Observer::Config.new(agent_name)
96
- config.options.merge!(options) if options.any?
97
- builder = Observer::Builder.new(agent_name, config)
98
- builder.instance_eval(&block)
99
-
100
- @observer_configs << config
101
- end
102
-
103
- # Add swarm-level hook (swarm_start, swarm_stop only)
104
- #
105
- # @example Shell command
106
- # hook :swarm_start, command: "echo 'Starting' >> log.txt"
107
- #
108
- # @example Ruby block
109
- # hook :swarm_start do |ctx|
110
- # puts "Swarm starting: #{ctx.metadata[:prompt]}"
111
- # end
112
- def hook(event, command: nil, timeout: nil, &block)
113
- # Validate swarm-level events
114
- unless [:swarm_start, :swarm_stop].include?(event)
115
- raise ArgumentError, "Invalid swarm-level hook: #{event}. Only :swarm_start and :swarm_stop allowed at swarm level. Use all_agents { hook ... } or agent { hook ... } for other events."
116
- end
117
-
118
- @swarm_hooks << { event: event, command: command, timeout: timeout, block: block }
119
- end
120
-
121
- # Build the actual Swarm instance
122
- def build_swarm
123
- raise ConfigurationError, "Swarm name not set. Use: name 'My Swarm'" unless @swarm_name
124
- raise ConfigurationError, "No agents defined. Use: agent :name { ... }" if @agents.empty?
125
- raise ConfigurationError, "Lead agent not set. Use: lead :agent_name" unless @lead_agent
126
-
127
- # Validate filesystem tools BEFORE building
128
- validate_all_agents_filesystem_tools if @all_agents_config
129
- validate_agent_filesystem_tools
130
-
131
- build_single_swarm
132
- end
133
-
134
- private
135
-
136
- # Build a traditional single-swarm execution
137
- #
138
- # @return [Swarm] Configured swarm instance
139
- def build_single_swarm
140
- # Validate swarm_id is set if external swarms are registered (required for composable swarms)
141
- if @swarm_registry_config.any? && @swarm_id.nil?
142
- raise ConfigurationError, "Swarm id must be set using id(...) when using composable swarms"
143
- end
144
-
145
- # Create swarm using SDK (swarm_id auto-generates if nil)
146
- swarm = Swarm.new(
147
- name: @swarm_name,
148
- swarm_id: @swarm_id,
149
- scratchpad_mode: @scratchpad,
150
- allow_filesystem_tools: @allow_filesystem_tools,
151
- execution_timeout: @execution_timeout,
152
- )
153
-
154
- # Setup swarm registry if external swarms are registered
155
- if @swarm_registry_config.any?
156
- registry = SwarmRegistry.new(parent_swarm_id: @swarm_id)
157
- @swarm_registry_config.each do |reg|
158
- registry.register(reg[:name], source: reg[:source], keep_context: reg[:keep_context])
159
- end
160
- swarm.swarm_registry = registry
161
- end
162
-
163
- # Build agent definitions and add to swarm
164
- agent_definitions = build_agent_definitions
165
- agent_definitions.each_value do |definition|
166
- swarm.add_agent(definition)
167
- end
168
-
169
- # Set lead
170
- swarm.lead = @lead_agent
171
-
172
- # Apply swarm hooks (Ruby blocks)
173
- @swarm_hooks.each do |hook_config|
174
- apply_swarm_hook(swarm, hook_config)
175
- end
176
-
177
- # Apply all_agents hooks (Ruby blocks)
178
- @all_agents_config&.hooks&.each do |hook_config|
179
- apply_all_agents_hook(swarm, hook_config)
180
- end
181
-
182
- # Add observer configurations to swarm
183
- @observer_configs.each { |c| swarm.add_observer_config(c) }
184
-
185
- swarm
186
- end
187
-
188
- def apply_swarm_hook(swarm, config)
189
- event = config[:event]
190
-
191
- if config[:block]
192
- # Ruby block hook - register directly
193
- swarm.add_default_callback(event, &config[:block])
194
- elsif config[:command]
195
- # Shell command hook - use ShellExecutor
196
- swarm.add_default_callback(event) do |context|
197
- input_json = build_hook_input(context, event)
198
- Hooks::ShellExecutor.execute(
199
- command: config[:command],
200
- input_json: input_json,
201
- timeout: config[:timeout] || 60,
202
- swarm_name: swarm.name,
203
- event: event,
204
- )
205
- end
206
- end
207
- end
208
-
209
- def apply_all_agents_hook(swarm, config)
210
- event = config[:event]
211
- matcher = config[:matcher]
212
-
213
- if config[:block]
214
- # Ruby block hook
215
- swarm.add_default_callback(event, matcher: matcher, &config[:block])
216
- elsif config[:command]
217
- # Shell command hook
218
- swarm.add_default_callback(event, matcher: matcher) do |context|
219
- input_json = build_hook_input(context, event)
220
- Hooks::ShellExecutor.execute(
221
- command: config[:command],
222
- input_json: input_json,
223
- timeout: config[:timeout] || 60,
224
- agent_name: context.agent_name,
225
- swarm_name: swarm.name,
226
- event: event,
227
- )
228
- end
229
- end
230
- end
231
-
232
- def build_hook_input(context, event)
233
- # Build JSON input for shell hooks
234
- base = { event: event.to_s }
235
-
236
- case event
237
- when :pre_tool_use
238
- base.merge(tool: context.tool_call.name, parameters: context.tool_call.parameters)
239
- when :post_tool_use
240
- base.merge(result: context.tool_result.content, success: context.tool_result.success?)
241
- when :user_prompt
242
- base.merge(prompt: context.metadata[:prompt])
243
- when :swarm_start
244
- base.merge(prompt: context.metadata[:prompt])
245
- when :swarm_stop
246
- base.merge(success: context.metadata[:success], duration: context.metadata[:duration])
247
- else
248
- base
249
- end
250
- end
251
- end
252
-
253
- # Helper class for swarms block in DSL (kept in this file for reference)
254
- # Actual implementation is in swarm_registry_builder.rb for Zeitwerk
255
- end
256
- end